/** Tests for attempt deleted event */ public function test_attempt_deleted_event() { global $USER; $this->resetAfterTest(); scorm_insert_track(2, $this->eventscorm->id, 1, 4, 'cmi.core.score.raw', 10); $sink = $this->redirectEvents(); scorm_delete_attempt(2, $this->eventscorm, 4); $events = $sink->get_events(); $sink->close(); $event = reset($events); // Verify data. $this->assertCount(3, $events); $this->assertInstanceOf('\\mod_scorm\\event\\attempt_deleted', $event); $this->assertEquals($USER->id, $event->userid); $this->assertEquals(context_module::instance($this->eventcm->id), $event->get_context()); $this->assertEquals(4, $event->other['attemptid']); $this->assertEquals(2, $event->relateduserid); $expected = array($this->eventcourse->id, 'scorm', 'delete attempts', 'report.php?id=' . $this->eventcm->id, 4, $this->eventcm->id); $this->assertEventLegacyLogData($expected, $events[0]); $this->assertEventContextNotUsed($event); // Test event validations. $this->setExpectedException('coding_exception'); \mod_scorm\event\attempt_deleted::create(array('contextid' => 5, 'relateduserid' => 2)); $this->fail('event \\mod_scorm\\event\\attempt_deleted is not validating events properly'); }
private static function scorm_start_time($userid, $scormid, $scoid, $attempts, $starttime) { global $DB; if ($attempts == '') { $attempts = 1; } $data = array_values($DB->get_records_sql("SELECT id FROM mdl_scorm_scoes_track WHERE userid = " . $userid . " AND scormid = " . $scormid . " AND scoid = " . $scoid . " AND attempt = " . $attempts . " AND element LIKE 'x.start.time' ORDER BY id DESC")); //$res['scormid'] = $data[0]->id; if (!empty($data)) { } else { $id = scorm_insert_track($userid, $scormid, $scoid, $attempts, 'x.start.time', $starttime); } }
$index = 0; foreach ($objectives as $objective) { if (!empty($objective->minnormalizedmeasure)) { $userdata->{'cmi.scaled_passing_score'} = $objective->minnormalizedmeasure; } if (!empty($objective->objectiveid)) { $userdata->{'cmi.objectives.N'.$index.'.id'} = $objective->objectiveid; $index++; } } } header('Content-Type: text/javascript; charset=UTF-8'); $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR)); // Just to be safe. if (file_exists($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'.js.php')) { include_once($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'.js.php'); } else { include_once($CFG->dirroot.'/mod/scorm/datamodels/scorm_12.js.php'); } // Set the start time of this SCO. scorm_insert_track($USER->id, $scorm->id, $scoid, $attempt, 'x.start.time', time()); ?> var errorCode = "0"; function underscore(str) { str = String(str).replace(/.N/g,"."); return str.replace(/\./g,"__"); }
/** * Test get scorm sco tracks */ public function test_mod_scorm_get_scorm_sco_tracks() { global $DB; $this->resetAfterTest(true); // Create users. $student = self::getDataGenerator()->create_user(); $otherstudent = self::getDataGenerator()->create_user(); $teacher = self::getDataGenerator()->create_user(); // Set to the student user. self::setUser($student); // Create courses to add the modules. $course = self::getDataGenerator()->create_course(); // First scorm. $record = new stdClass(); $record->course = $course->id; $scorm = self::getDataGenerator()->create_module('scorm', $record); // Users enrolments. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $teacherrole = $DB->get_record('role', array('shortname' => 'teacher')); $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); // Create attempts. $scoes = scorm_get_scoes($scorm->id); $sco = array_shift($scoes); scorm_insert_track($student->id, $scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed'); scorm_insert_track($student->id, $scorm->id, $sco->id, 1, 'cmi.core.score.raw', '80'); scorm_insert_track($student->id, $scorm->id, $sco->id, 2, 'cmi.core.lesson_status', 'completed'); $result = mod_scorm_external::get_scorm_sco_tracks($sco->id, $student->id, 1); $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_sco_tracks_returns(), $result); // 7 default elements + 2 custom ones. $this->assertCount(9, $result['data']['tracks']); $this->assertEquals(1, $result['data']['attempt']); $this->assertCount(0, $result['warnings']); // Find our tracking data. $found = 0; foreach ($result['data']['tracks'] as $userdata) { if ($userdata['element'] == 'cmi.core.lesson_status' and $userdata['value'] == 'completed') { $found++; } if ($userdata['element'] == 'cmi.core.score.raw' and $userdata['value'] == '80') { $found++; } } $this->assertEquals(2, $found); // Try invalid attempt. $result = mod_scorm_external::get_scorm_sco_tracks($sco->id, $student->id, 10); $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_sco_tracks_returns(), $result); $this->assertCount(0, $result['data']['tracks']); $this->assertEquals(10, $result['data']['attempt']); $this->assertCount(1, $result['warnings']); $this->assertEquals('notattempted', $result['warnings'][0]['warningcode']); // Capabilities check. try { mod_scorm_external::get_scorm_sco_tracks($sco->id, $otherstudent->id); $this->fail('Exception expected due to invalid instance id.'); } catch (required_capability_exception $e) { $this->assertEquals('nopermissions', $e->errorcode); } self::setUser($teacher); // Ommit the attempt parameter, the function should calculate the last attempt. $result = mod_scorm_external::get_scorm_sco_tracks($sco->id, $student->id); $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_sco_tracks_returns(), $result); // 7 default elements + 1 custom one. $this->assertCount(8, $result['data']['tracks']); $this->assertEquals(2, $result['data']['attempt']); // Test invalid instance id. try { mod_scorm_external::get_scorm_sco_tracks(0, 1); $this->fail('Exception expected due to invalid instance id.'); } catch (moodle_exception $e) { $this->assertEquals('cannotfindsco', $e->errorcode); } // Invalid user. try { mod_scorm_external::get_scorm_sco_tracks($sco->id, 0); $this->fail('Exception expected due to invalid instance id.'); } catch (moodle_exception $e) { $this->assertEquals('invaliduser', $e->errorcode); } }
function scorm_seq_set($what, $scoid, $userid, $attempt = 0, $value = 'true') { global $DB; $sco = scorm_get_sco($scoid); // Set passed activity to active or not. if ($value == false) { $DB->delete_records('scorm_scoes_track', array('scoid' => $scoid, 'userid' => $userid, 'attempt' => $attempt, 'element' => $what)); } else { scorm_insert_track($userid, $sco->scorm, $sco->id, $attempt, $what, $value); } // Update grades in gradebook. $scorm = $DB->get_record('scorm', array('id' => $sco->scorm)); scorm_update_grades($scorm, $userid, true); }
if ($mode == 'browse' && $initlessonstatus == 'not attempted') { $lessonstatus = 'browsed'; $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', 'browsed'); } if ($mode == 'normal') { if ($sco = scorm_get_sco($scoid)) { if (!empty($sco->mastery_score)) { if (!empty($score)) { if ($score >= $sco->mastery_score) { $lessonstatus = 'passed'; } else { $lessonstatus = 'failed'; } } } $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', $lessonstatus); } } } echo "error=0\r\nerror_text=Successful\r\n"; } else { if ($status == 'Terminated') { echo "error=1\r\nerror_text=Terminated\r\n"; } else { echo "error=1\r\nerror_text=Not Initialized\r\n"; } } break; case 'putcomments': if ($status == 'Running') { echo "error=0\r\nerror_text=Successful\r\n";
} } } } // // If no sco was found get the first of SCORM package // if (!isset($sco)) { $scoes = $DB->get_records_select('scorm_scoes', "scorm = ? AND launch <> ?", array($scorm->id, $DB->sql_empty()), 'id ASC'); $sco = current($scoes); } if ($sco->scormtype == 'asset') { $attempt = scorm_get_last_attempt($scorm->id, $USER->id); $element = $scorm->version == 'scorm_13' || $scorm->version == 'SCORM_1.3' ? 'cmi.completion_status' : 'cmi.core.lesson_status'; $value = 'completed'; $result = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value); } // // Forge SCO URL // $connector = ''; $version = substr($scorm->version, 0, 4); if (isset($sco->parameters) && !empty($sco->parameters) || $version == 'AICC') { if (stripos($sco->launch, '?') !== false) { $connector = '&'; } else { $connector = '?'; } if (isset($sco->parameters) && !empty($sco->parameters) && $sco->parameters[0] == '?') { $sco->parameters = substr($sco->parameters, 1); }
function JLMS_LoadSCOSCORM($option) { global $JLMS_DB, $my, $Itemid; $JLMS_CONFIG =& JLMSFactory::getConfig(); $id = intval(mosGetParam($_REQUEST, 'id', 0)); $delayseconds = 20; // Delay time before sco launch, used to give time to browser to define API $delayseconds_nojs = 2; // if API were defined earlier than timer is passed - SCO will be launched if ($id) { $query = "SELECT * FROM #__lms_n_scorm WHERE id = {$id}"; $JLMS_DB->SetQuery($query); $scorm = $JLMS_DB->LoadObject(); if (is_object($scorm)) { $scoid = intval(mosGetParam($_REQUEST, 'scoid', 0)); if (!empty($scoid)) { // // Direct SCO request // if ($sco = scorm_get_sco($scoid)) { // (DEN) check if this $scoid from our SCORM !!!! if ($sco->launch == '') { // Search for the next launchable sco $query = "SELECT * FROM #__lms_n_scorm_scoes WHERE scorm = {$scorm->id} AND launch <> '' AND id > {$sco->id} ORDER BY id ASC"; $JLMS_DB->SetQuery($query); $scoes = $JLMS_DB->LoadObjectList(); //if ($scoes = get_records_select('scorm_scoes','scorm='.$scorm->id." AND launch<>'' AND id>".$sco->id,'id ASC')) { if (!empty($scoes)) { $sco = current($scoes); } } } } // // If no sco was found get the first of SCORM package // if (!isset($sco)) { $query = "SELECT * FROM #__lms_n_scorm_scoes WHERE scorm = {$scorm->id} AND launch <> '' ORDER BY id ASC"; $JLMS_DB->SetQuery($query); $scoes = $JLMS_DB->LoadObjectList(); //$scoes = get_records_select('scorm_scoes','scorm='.$scorm->id." AND launch<>''",'id ASC'); $sco = current($scoes); } if (!empty($sco)) { if ($sco->scormtype == 'asset') { $attempt = scorm_get_last_attempt($scorm->id, $my->id); $element = $scorm->version == 'scorm_13' ? 'cmi.completion_status' : 'cmi.core.lesson_status'; $value = 'completed'; $result = scorm_insert_track($my->id, $scorm->id, $sco->id, $attempt, $element, $value); } } // // Forge SCO URL // $connector = ''; $version = substr($scorm->version, 0, 4); if (isset($sco->parameters) && !empty($sco->parameters) || $version == 'AICC') { /** * 06.10.2007 (DEN) "''." - is added for compatibility with Joomla compatibility :)) library compat.php50x.php (on line 105 in PHP 4.4.7 there was a notice) */ if (stripos('' . $sco->launch, '?') !== false) { $connector = '&'; } else { $connector = '?'; } if (isset($sco->parameters) && !empty($sco->parameters) && $sco->parameters[0] == '?') { $sco->parameters = substr($sco->parameters, 1); } } if ($version == 'AICC') { if (isset($sco->parameters) && !empty($sco->parameters)) { $sco->parameters = '&' . $sco->parameters; } //$launcher = $sco->launch.$connector.'aicc_sid='.$my->id.'&aicc_url='.$CFG->wwwroot.'/mod/scorm/aicc.php'.$sco->parameters; $launcher = $sco->launch . $connector . 'aicc_sid=' . $my->id . '&aicc_url=' . $JLMS_CONFIG->get('live_site') . "/index.php?option={$option}&Itemid={$Itemid}&task=aicc_task&course_id={$course_id}" . $sco->parameters; // (DEN) check this URL /\ !!!!!!!!! } else { if (isset($sco->parameters) && !empty($sco->parameters)) { $launcher = $sco->launch . $connector . $sco->parameters; } else { $launcher = $sco->launch; } } $query = "SELECT * FROM #__lms_scorm_packages WHERE id = {$scorm->scorm_package}"; $JLMS_DB->SetQuery($query); $scorm_ref = $JLMS_DB->LoadObject(); //$reference = $CFG->dataroot.'/'.$courseid.'/'.$reference; //$row->reference = _JOOMLMS_SCORM_FOLDER_PATH . "/" . $scorm_ref->package_srv_name; $reference_folder = $JLMS_CONFIG->get('live_site') . "/" . _JOOMLMS_SCORM_PLAYER . "/" . $scorm_ref->folder_srv_name; //$reference_folder = _JOOMLMS_SCORM_FOLDER_PATH . "/" . $scorm_ref->folder_srv_name; // (DEN) we don't use external links nor repositry (but maybe...maybe...) /*if (scorm_external_link($sco->launch)) { // Remote learning activity $result = $launcher; } else if ($scorm->reference[0] == '#') { // Repository require_once($repositoryconfigfile); $result = $CFG->repositorywebroot.substr($scorm->reference,1).'/'.$sco->launch; } else {*/ if (true) { // (DEN) we don't use external packages /*if ((basename($scorm->reference) == 'imsmanifest.xml') && scorm_external_link($scorm->reference)) { // Remote manifest $result = dirname($scorm->reference).'/'.$launcher; } else {*/ if (true) { // Moodle internal package/manifest or remote (auto-imported) package //if (basename($scorm->reference) == 'imsmanifest.xml') { if (basename($reference_folder) == 'imsmanifest.xml') { //$basedir = dirname($scorm->reference); $basedir = dirname($reference_folder); } else { $basedir = $reference_folder; //$CFG->moddata.'/scorm/'.$scorm->id; } /*if ($CFG->slasharguments) { $result = $CFG->wwwroot.'/file.php/'.$scorm->course.'/'.$basedir.'/'.$launcher; } else { $result = $CFG->wwwroot.'/file.php?file=/'.$scorm->course.'/'.$basedir.'/'.$launcher; }*/ $result = $reference_folder . '/' . $launcher; // determine the name of the API variable, which are we looking for $LMS_api = $scorm->version == 'scorm_12' || $scorm->version == 'SCORM_1.2' || empty($scorm->version) ? 'API' : 'API_1484_11'; if (isset($sco->scormtype) && strtolower($sco->scormtype) == 'asset') { $delayseconds = 2; // if resource is 'asset' - we don't need SCORM API } ?> <html> <head> <title>LoadSCO</title> <script type="text/javascript"> //<![CDATA[ var delaySeconds = <?php echo $delayseconds; ?> function findscormAPI(win) { var findAPITries = 0; while ((win.<?php echo $LMS_api; ?> == null) && (win.parent != null) && (win.parent != win)) { findAPITries++; if (findAPITries > 7) { // we don't have more than 7 nested window objects.... return null; } win = win.parent; } return win.<?php echo $LMS_api; ?> ; } function getscormAPI() { var theAPI = findscormAPI(window); if ((theAPI == null) && (window.opener != null) && (typeof(window.opener) != "undefined")) { theAPI = findscormAPI(window.opener); } if (theAPI == null) { return null; } return theAPI; } function try_redirect() { if (getscormAPI() == null) { delaySeconds = delaySeconds - 1; if (delaySeconds < 0) { setTimeout('do_window_redirect();',1000); } else { setTimeout('try_redirect();',1000); } } else { setTimeout('do_window_redirect();',1000); } } function do_window_redirect() { document.location = "<?php echo $result; ?> "; } //]]> </script> <noscript> <meta http-equiv="refresh" content="<?php echo $delayseconds_nojs; ?> ;url=<?php echo $result; ?> " /> </noscript> </head> <body onload="try_redirect();"> <br /><br /><center><img src="<?php echo $JLMS_CONFIG->get('live_site'); ?> /components/com_joomla_lms/lms_images/loading.gif" height="32" width="32" border="0" alt="loading" /></center> </body> </html> <?php } } } } die; }
function scorm_content_delivery_environment($seq, $userid) { $act = $seq->currentactivity; if (scorm_seq_is('active', $act->id, $userid)) { $seq->exception = 'DB.2-1'; return $seq; } $track = get_record('scorm_scoes_track', 'scoid', $act->id, 'userid', $userid, 'element', 'suspendedactivity'); if ($track != null) { $seq = scorm_clear_suspended_activity($seq->delivery, $seq); } $seq = scorm_terminate_descendent_attempts($seq->delivery, $userid, $seq); $ancestors = scorm_get_ancestors($seq->delivery); $arrpath = array_reverse($ancestors); array_push($arrpath, $seq->delivery); foreach ($arrpath as $activity) { if (!scorm_seq_is('active', $activity->id, $userid)) { if (!isset($activity->tracked) || $activity->tracked == 1) { if (!scorm_seq_is('suspended', $activity->id, $userid)) { $r = get_record('scorm_scoes_track', 'scoid', $activity->id, 'userid', $userid, 'element', 'activityattemptcount'); $r->value = $r->value + 1; update_record('scorm_scoes_track', $r); if ($r->value == 1) { scorm_seq_set('activityprogressstatus', $activity->id, $userid, 'true'); } scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectiveprogressstatus', 'false'); scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivesatisfiedstatus', 'false'); scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivemeasurestatus', 'false'); scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'objectivenormalizedmeasure', 0.0); scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptprogressstatus', 'false'); scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionstatus', 'false'); scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptabsoluteduration', 0.0); scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptexperiencedduration', 0.0); scorm_insert_track($userid, $activity->scorm, $activity->id, 0, 'attemptcompletionamount', 0.0); } } scorm_seq_set('active', $activity->id, $userid, 'true'); } } $seq->delivery = $seq->currentactivity; scorm_seq_set('suspendedactivity', $activity->id, $userid, 'false'); //ONCE THE DELIVERY BEGINS (How should I check that?) if (isset($activity->tracked) || $activity->tracked == 0) { //How should I track the info and what should I do to not record the information for the activity during delivery? $atabsdur = get_record('scorm_scoes_track', 'scoid', $activity->id, 'userid', $userid, 'element', 'attemptabsoluteduration'); $atexpdur = get_record('scorm_scoes_track', 'scoid', $activity->id, 'userid', $userid, 'element', 'attemptexperiencedduration'); } return $seq; }
/** * Saves a SCORM tracking record. * It will overwrite any existing tracking data for this attempt. * Validation should be performed before running the function to ensure the user will not lose any existing attempt data. * * @param int $scoid the SCO id * @param string $attempt the attempt number * @param array $tracks the track records to be stored * @return array warnings and the scoes data * @throws moodle_exception * @since Moodle 3.0 */ public static function insert_scorm_tracks($scoid, $attempt, $tracks) { global $USER, $DB; $params = self::validate_parameters(self::insert_scorm_tracks_parameters(), array('scoid' => $scoid, 'attempt' => $attempt, 'tracks' => $tracks)); $trackids = array(); $warnings = array(); $sco = scorm_get_sco($params['scoid'], SCO_ONLY); if (!$sco) { throw new moodle_exception('cannotfindsco', 'scorm'); } $scorm = $DB->get_record('scorm', array('id' => $sco->scorm), '*', MUST_EXIST); $cm = get_coursemodule_from_instance('scorm', $scorm->id); $context = context_module::instance($cm->id); self::validate_context($context); // Check settings / permissions to view the SCORM. require_capability('mod/scorm:savetrack', $context); // Check settings / permissions to view the SCORM. scorm_require_available($scorm); foreach ($params['tracks'] as $track) { $element = $track['element']; $value = $track['value']; $trackid = scorm_insert_track($USER->id, $scorm->id, $sco->id, $params['attempt'], $element, $value, $scorm->forcecompleted); if ($trackid) { $trackids[] = $trackid; } else { $warnings[] = array('item' => 'scorm', 'itemid' => $scorm->id, 'warningcode' => 1, 'message' => 'Element: ' . $element . ' was not saved'); } } $result = array(); $result['trackids'] = $trackids; $result['warnings'] = $warnings; return $result; }
error("Course Module ID was incorrect"); } } else { error('A required parameter is missing'); } } require_login($course->id, false, $cm); if (confirm_sesskey() && !empty($scoid)) { $result = true; $request = null; if (has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE, $cm->id))) { foreach ($_POST as $element => $value) { $element = str_replace('__', '.', $element); if (substr($element, 0, 3) == 'cmi') { $netelement = preg_replace('/\\.N(\\d+)\\./', "\\.\$1\\.", $element); $result = scorm_insert_track($USER->id, $scorm->id, $scoid, $attempt, $netelement, $value) && $result; } if (substr($element, 0, 15) == 'adl.nav.request') { // SCORM 2004 Sequencing Request require_once 'datamodels/sequencinglib.php'; $search = array('@continue@', '@previous@', '@\\{target=(\\S+)\\}choice@', '@exit@', '@exitAll@', '@abandon@', '@abandonAll@'); $replace = array('continue_', 'previous_', '\\1', 'exit_', 'exitall_', 'abandon_', 'abandonall'); $action = preg_replace($search, $replace, $value); if ($action != $value) { // Evaluating navigation request $valid = scorm_seq_overall($scoid, $USER->id, $action, $attempt); $valid = 'true'; // Set valid request $search = array('@continue@', '@previous@', '@\\{target=(\\S+)\\}choice@'); $replace = array('true', 'true', 'true'); $matched = preg_replace($search, $replace, $value);
} } else { print_error('missingparameter'); } } $PAGE->set_url('/mod/scorm/datamodel.php', array('scoid' => $scoid, 'attempt' => $attempt, 'id' => $cm->id)); require_login($course, false, $cm); if (confirm_sesskey() && !empty($scoid)) { $result = true; $request = null; if (has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE, $cm->id))) { foreach (data_submitted() as $element => $value) { $element = str_replace('__', '.', $element); if (substr($element, 0, 3) == 'cmi') { $netelement = preg_replace('/\\.N(\\d+)\\./', "\\.\$1\\.", $element); $result = scorm_insert_track($USER->id, $scorm->id, $scoid, $attempt, $element, $value, $scorm->forcecompleted) && $result; } if (substr($element, 0, 15) == 'adl.nav.request') { // SCORM 2004 Sequencing Request require_once $CFG->dirroot . '/mod/scorm/datamodels/sequencinglib.php'; $search = array('@continue@', '@previous@', '@\\{target=(\\S+)\\}choice@', '@exit@', '@exitAll@', '@abandon@', '@abandonAll@'); $replace = array('continue_', 'previous_', '\\1', 'exit_', 'exitall_', 'abandon_', 'abandonall'); $action = preg_replace($search, $replace, $value); if ($action != $value) { // Evaluating navigation request $valid = scorm_seq_overall($scoid, $USER->id, $action, $attempt); $valid = 'true'; // Set valid request $search = array('@continue@', '@previous@', '@\\{target=(\\S+)\\}choice@'); $replace = array('true', 'true', 'true'); $matched = preg_replace($search, $replace, $value);
function scorm_seq_set($what, $scoid, $userid, $attempt = 0, $value = 'true') { /// set passed activity to active or not if ($value == false) { delete_record('scorm_scoes_track', 'scoid', $scoid, 'userid', $userid, 'element', $what); } else { $sco = scorm_get_sco($scoid); scorm_insert_track($userid, $sco->scorm, $sco->id, 0, $what, $value); } }
function scorm_tcapi_store_statement($params, $statementObject) { global $CFG, $USER, $DB, $SESSION; if (isset($params['actor']) && isset($params['actor']->moodle_user)) $userid = $params['actor']->moodle_user; else $userid = $USER->id; if (isset($params['moodle_mod_id'])) $scoid = $params['moodle_mod_id']; else throw new invalid_parameter_exception('Module id not provided.'); require_once($CFG->dirroot.'/mod/scorm/locallib.php'); if (($sco = scorm_get_sco($scoid)) && ($attempt = scorm_get_last_attempt($sco->scorm, $userid))) { $usertrack = scorm_get_tracks($scoid, $userid, $attempt); // if the activity is considered complete, only update the time if it doesn't yet exist $attempt_complete = ($usertrack && (($usertrack->status == 'completed') || ($usertrack->status == 'passed') || ($usertrack->status == 'failed'))); $statement = $statementObject->statement; $statementRow = $statementObject->statementRow; // check that the incoming statement refers to the sco identifier if (isset($statement->activity)) { $sco_activity = $statement->activity; // TODO: Add support for interaction tracks for child results reporting. //if (!empty($statement->activity->grouping_id) && ($lrs_activity = $DB->get_record_select('tcapi_activity','id = ?',array($statement->activity->grouping_id)))) //$sco_activity = $lrs_activity; if ($sco->identifier == $sco_activity->activity_id) { // check for existing cmi.core.lesson_status // set default to 'incomplete' // check statement->verb and set cmi.core.lesson_status as appropriate $cmiCoreLessonStatus = (empty($usertrack->status) || $usertrack->status == 'notattempted') ? 'incomplete' : $usertrack->status; if (in_array(strtolower($statementRow->verb),array('completed','passed','mastered','failed'))) { $cmiCoreLessonStatus = strtolower($statementRow->verb); // Indicates activity status is complete $complStatus = ($cmiCoreLessonStatus !== 'failed') ? 'completed' : 'incomplete'; if (!$attempt_complete) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.completion_status', $complStatus); // Create/update track for cmi.core.lesson_status if (!$attempt_complete && in_array($cmiCoreLessonStatus,array('passed','failed','completed','incomplete'))) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.lesson_status', $cmiCoreLessonStatus); if (!$attempt_complete && in_array($cmiCoreLessonStatus,array('passed','failed'))) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.success_status', $cmiCoreLessonStatus); elseif (!isset($usertrack->{'cmi.success_status'})) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.success_status', 'unknown'); // check if any result was reported if (isset($statementObject->resultRow)) { $result = $statementObject->resultRow; // if a duration was reported, add to any existing total_time if (isset($result->duration)) { if ($usertrack->total_time == '00:00:00') $total_time = $result->duration; elseif (!$attempt_complete) $total_time = scorm_tcapi_add_time($result->duration, $usertrack->total_time); if (isset($total_time)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.total_time', $total_time); } if (isset($result->score) && !$attempt_complete) { $score = json_decode($result->score); if (isset($score->raw)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.raw', $score->raw); if (isset($score->min)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.min', $score->min); if (isset($score->max)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.max', $score->max); // if scaled is provided but no raw, calculate the raw as we need it for SCORM grades // try to use the min/max if available. if not, use 0/100 if (isset($score->scaled)) { if (!isset($score->raw)) { $scoremin = (isset($score->min)) ? $score->min : 0; $scoremax = (isset($score->max)) ? $score->max : 100; $score->raw = ($score->scaled*($scoremax-$scoremin))+$scoremin; scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.raw', $score->raw); if (!isset($score->min)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.min', $scoremin); if (!isset($score->max)) scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.score.max', $scoremax); } scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.score.scaled', $score->scaled); } } } } if ($attempt_complete) return $statementObject->statementId; // set cmi.core.exit to suspend if status is incomplete, else remove the track entry if ($cmiCoreLessonStatus == 'incomplete') scorm_insert_track($userid, $sco->scorm, $scoid, $attempt, 'cmi.core.exit', 'suspend'); elseif ($track = $DB->get_record('scorm_scoes_track', array('userid'=>$userid, 'scormid'=>$sco->scorm, 'scoid'=>$scoid, 'attempt'=>$attempt, 'element'=>'cmi.core.exit'))) $DB->delete_records_select('scorm_scoes_track', 'id = ?', array($track->id)); } } } else throw new invalid_parameter_exception('Parameters invalid or Scorm/Sco not found.'); return $statementObject->statementId; }