mirror of
https://github.com/moodle/moodle.git
synced 2025-04-20 16:04:25 +02:00
Merge branch 'MDL-46279' of https://github.com/danmarsden/moodle
This commit is contained in:
commit
01593b9332
@ -77,7 +77,7 @@ if (!empty($command)) {
|
||||
} else {
|
||||
$attempt = 1;
|
||||
}
|
||||
|
||||
$attemptobject = scorm_get_attempt($aiccuser->id, $scormsession->scormid, $attempt);
|
||||
if ($sco = scorm_get_sco($scoid, SCO_ONLY)) {
|
||||
if (!$scorm = $DB->get_record('scorm', array('id' => $sco->scorm))) {
|
||||
throw new \moodle_exception('cannotcallscript');
|
||||
@ -226,7 +226,7 @@ if (!empty($command)) {
|
||||
switch ($element) {
|
||||
case 'cmi.core.lesson_location':
|
||||
$id = scorm_insert_track($aiccuser->id, $scorm->id, $sco->id,
|
||||
$attempt, $element, $value);
|
||||
$attemptobject, $element, $value);
|
||||
break;
|
||||
case 'cmi.core.lesson_status':
|
||||
$statuses = array(
|
||||
@ -263,14 +263,14 @@ if (!empty($command)) {
|
||||
if (empty($value) || isset($exites[$value])) {
|
||||
$subelement = 'cmi.core.exit';
|
||||
$id = scorm_insert_track($aiccuser->id, $scorm->id, $sco->id,
|
||||
$attempt, $subelement, $value);
|
||||
$attemptobject, $subelement, $value);
|
||||
}
|
||||
$value = trim(strtolower($values[0]));
|
||||
$value = $value[0];
|
||||
if (isset($statuses[$value]) && ($mode == 'normal')) {
|
||||
$value = $statuses[$value];
|
||||
$id = scorm_insert_track($aiccuser->id, $scorm->id, $sco->id,
|
||||
$attempt, $element, $value);
|
||||
$attemptobject, $element, $value);
|
||||
}
|
||||
$lessonstatus = $value;
|
||||
break;
|
||||
@ -280,12 +280,12 @@ if (!empty($command)) {
|
||||
$subelement = 'cmi.core.score.max';
|
||||
$value = trim($values[1]);
|
||||
$id = scorm_insert_track($aiccuser->id, $scorm->id, $sco->id,
|
||||
$attempt, $subelement, $value);
|
||||
$attemptobject, $subelement, $value);
|
||||
if ((count($values) == 3) && ($values[2] <= $values[0]) && is_numeric($values[2])) {
|
||||
$subelement = 'cmi.core.score.min';
|
||||
$value = trim($values[2]);
|
||||
$id = scorm_insert_track($aiccuser->id, $scorm->id, $sco->id,
|
||||
$attempt, $subelement, $value);
|
||||
$attemptobject, $subelement, $value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -293,7 +293,7 @@ if (!empty($command)) {
|
||||
if (is_numeric($values[0])) {
|
||||
$value = trim($values[0]);
|
||||
$id = scorm_insert_track($aiccuser->id, $scorm->id, $sco->id,
|
||||
$attempt, $element, $value);
|
||||
$attemptobject, $element, $value);
|
||||
}
|
||||
$score = $value;
|
||||
break;
|
||||
@ -311,14 +311,14 @@ if (!empty($command)) {
|
||||
next($datarows);
|
||||
}
|
||||
$value = rawurlencode($value);
|
||||
$id = scorm_insert_track($aiccuser->id, $scorm->id, $sco->id, $attempt, $element, $value);
|
||||
$id = scorm_insert_track($aiccuser->id, $scorm->id, $sco->id, $attemptobject, $element, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (($mode == 'browse') && ($initlessonstatus == 'not attempted')) {
|
||||
$lessonstatus = 'browsed';
|
||||
$id = scorm_insert_track($aiccuser->id, $scorm->id, $sco->id,
|
||||
$attempt, 'cmi.core.lesson_status', 'browsed');
|
||||
$attemptobject, 'cmi.core.lesson_status', 'browsed');
|
||||
}
|
||||
if ($mode == 'normal') {
|
||||
if ($sco = scorm_get_sco($scoid)) {
|
||||
@ -332,7 +332,7 @@ if (!empty($command)) {
|
||||
}
|
||||
}
|
||||
$id = scorm_insert_track($aiccuser->id, $scorm->id, $sco->id,
|
||||
$attempt, 'cmi.core.lesson_status', $lessonstatus);
|
||||
$attemptobject, 'cmi.core.lesson_status', $lessonstatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -391,26 +391,24 @@ if (!empty($command)) {
|
||||
case 'exitau':
|
||||
if ($status == 'Running') {
|
||||
if (isset($scormsession->sessiontime) && ($scormsession->sessiontime != '')) {
|
||||
if ($track = $DB->get_record('scorm_scoes_track', array("userid" => $aiccuser->id,
|
||||
"scormid" => $scorm->id,
|
||||
"scoid" => $sco->id,
|
||||
"attempt" => $attempt,
|
||||
"element" => 'cmi.core.total_time'))) {
|
||||
$track = scorm_get_sco_value($sco->id, $aiccuser->id, 'cmi.core.total_time', $attempt);
|
||||
if (!empty($track)) {
|
||||
// Add session_time to total_time.
|
||||
$value = scorm_add_time($track->value, $scormsession->sessiontime);
|
||||
$track->value = $value;
|
||||
$track->timemodified = time();
|
||||
$DB->update_record('scorm_scoes_track', $track);
|
||||
$v = new stdClass();
|
||||
$v->id = $track->valueid;
|
||||
$v->value = $value;
|
||||
$v->timemodified = time();
|
||||
$DB->update_record('scorm_scoes_value', $v);
|
||||
} else {
|
||||
$track = new stdClass();
|
||||
$track->userid = $aiccuser->id;
|
||||
$track->scormid = $scorm->id;
|
||||
$track->scoid = $sco->id;
|
||||
$track->element = 'cmi.core.total_time';
|
||||
$track->element = scorm_get_elementid('cmi.core.total_time');
|
||||
$track->value = $scormsession->sessiontime;
|
||||
$track->attempt = $attempt;
|
||||
$atobject = scorm_get_attempt($userid, $scormsession->scormid, $attempt);
|
||||
$track->attempt = $atobject->id;
|
||||
$track->timemodified = time();
|
||||
$id = $DB->insert_record('scorm_scoes_track', $track);
|
||||
$id = $DB->insert_record('scorm_scoes_value', $track);
|
||||
}
|
||||
scorm_update_grades($scorm, $aiccuser->id);
|
||||
}
|
||||
|
@ -141,7 +141,12 @@ class backup_scorm_activity_structure_step extends backup_activity_structure_ste
|
||||
|
||||
// All the rest of elements only happen if we are including user info
|
||||
if ($userinfo) {
|
||||
$scotrack->set_source_table('scorm_scoes_track', array('scoid' => backup::VAR_PARENTID), 'id ASC');
|
||||
$sql = 'SELECT v.id, a.userid, a.attempt, e.element, v.value, v.timemodified
|
||||
FROM {scorm_attempt} a
|
||||
JOIN {scorm_scoes_value} v ON v.attemptid = a.id
|
||||
JOIN {scorm_element} e ON e.id = v.elementid
|
||||
WHERE v.scoid = :scoid';
|
||||
$scotrack->set_source_sql($sql, ['scoid' => backup::VAR_PARENTID], 'id ASC');
|
||||
}
|
||||
|
||||
// Define id annotations
|
||||
|
@ -173,17 +173,19 @@ class restore_scorm_activity_structure_step extends restore_activity_structure_s
|
||||
}
|
||||
|
||||
protected function process_scorm_sco_track($data) {
|
||||
global $DB;
|
||||
|
||||
global $DB, $CFG;
|
||||
require_once($CFG->dirroot.'/mod/scorm/locallib.php');
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
$data->scormid = $this->get_new_parentid('scorm');
|
||||
$attemptobject = scorm_get_attempt($this->get_mappingid('user', $data->userid),
|
||||
$this->get_new_parentid('scorm'),
|
||||
$data->attempt);
|
||||
$data->scoid = $this->get_new_parentid('scorm_sco');
|
||||
$data->userid = $this->get_mappingid('user', $data->userid);
|
||||
$data->attemptid = $attemptobject->id;
|
||||
$data->elementid = scorm_get_elementid($data->element);
|
||||
|
||||
$newitemid = $DB->insert_record('scorm_scoes_track', $data);
|
||||
// No need to save this mapping as far as nothing depend on it
|
||||
// (child paths, file areas nor links decoder)
|
||||
$DB->insert_record('scorm_scoes_value', $data);
|
||||
// No need to save this mapping as far as nothing depend on it.
|
||||
}
|
||||
|
||||
protected function after_execute() {
|
||||
|
77
mod/scorm/classes/cache/elements.php
vendored
Normal file
77
mod/scorm/classes/cache/elements.php
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
// 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/>.
|
||||
|
||||
declare(strict_types=1);
|
||||
namespace mod_scorm\cache;
|
||||
use cache_definition;
|
||||
|
||||
/**
|
||||
* Cache data source for the scorm elements.
|
||||
*
|
||||
* @package mod_scorm
|
||||
* @copyright 2023 Catalyst IT Ltd
|
||||
* @author Dan Marsden <dan@danmarsden.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class elements implements \cache_data_source {
|
||||
|
||||
/** @var elements the singleton instance of this class. */
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* Returns an instance of the data source class that the cache can use for loading data using the other methods
|
||||
* specified by this interface.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @return object
|
||||
*/
|
||||
public static function get_instance_for_cache(cache_definition $definition): elements {
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new elements();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the data for the key provided ready formatted for caching.
|
||||
*
|
||||
* @param string|int $key The key to load.
|
||||
* @return string What ever data should be returned, or null if it can't be loaded.
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function load_for_cache($key): ?string {
|
||||
global $DB;
|
||||
|
||||
$element = $DB->get_field('scorm_element', 'id', ['element' => $key]);
|
||||
// Return null instead of false, because false will not be cached.
|
||||
return $element ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads several keys for the cache.
|
||||
*
|
||||
* @param array $keys An array of keys each of which will be string|int.
|
||||
* @return array An array of matching data items.
|
||||
*/
|
||||
public function load_many_for_cache(array $keys): array {
|
||||
global $DB;
|
||||
list ($elementsql, $params) = $DB->get_in_or_equal($keys);
|
||||
$sql = "SELECT element, id
|
||||
FROM {scorm_element}
|
||||
WHERE element ".$elementsql;
|
||||
return $DB->get_records_sql_menu($sql, $params);
|
||||
}
|
||||
}
|
@ -48,16 +48,18 @@ class custom_completion extends activity_custom_completion {
|
||||
$this->validate_rule($rule);
|
||||
|
||||
// Base query used when fetching user's tracks data.
|
||||
$basequery = "SELECT id, scoid, element, value
|
||||
FROM {scorm_scoes_track}
|
||||
WHERE scormid = ?
|
||||
AND userid = ?";
|
||||
$basequery = "SELECT v.id, v.scoid, e.element, v.value
|
||||
FROM {scorm_scoes_value} v
|
||||
JOIN {scorm_attempt} a ON a.id = v.attemptid
|
||||
JOIN {scorm_element} e ON e.id = v.elementid
|
||||
WHERE a.scormid = ?
|
||||
AND a.userid = ?";
|
||||
|
||||
switch ($rule) {
|
||||
case 'completionstatusrequired':
|
||||
$status = COMPLETION_INCOMPLETE;
|
||||
$query = $basequery .
|
||||
" AND element IN (
|
||||
" AND e.element IN (
|
||||
'cmi.core.lesson_status',
|
||||
'cmi.completion_status',
|
||||
'cmi.success_status'
|
||||
@ -85,7 +87,7 @@ class custom_completion extends activity_custom_completion {
|
||||
case 'completionscorerequired':
|
||||
$status = COMPLETION_INCOMPLETE;
|
||||
$query = $basequery .
|
||||
" AND element IN (
|
||||
" AND e.element IN (
|
||||
'cmi.core.score.raw',
|
||||
'cmi.score.raw'
|
||||
)";
|
||||
@ -110,7 +112,7 @@ class custom_completion extends activity_custom_completion {
|
||||
// Assume complete unless we find a sco that is not complete.
|
||||
$status = COMPLETION_COMPLETE;
|
||||
$query = $basequery .
|
||||
" AND element IN (
|
||||
" AND e.element IN (
|
||||
'cmi.core.lesson_status',
|
||||
'cmi.completion_status',
|
||||
'cmi.success_status'
|
||||
|
@ -49,7 +49,7 @@ abstract class cmielement_submitted extends \core\event\base {
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'u';
|
||||
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
|
||||
$this->data['objecttable'] = 'scorm_scoes_track';
|
||||
$this->data['objecttable'] = 'scorm_scoes_value';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -481,11 +481,12 @@ class mod_scorm_external extends external_api {
|
||||
|
||||
// Check settings / permissions to view the SCORM.
|
||||
scorm_require_available($scorm);
|
||||
$attemptobject = scorm_get_attempt($USER->id, $scorm->id, $params['attempt']);
|
||||
|
||||
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,
|
||||
$trackid = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attemptobject, $element, $value,
|
||||
$scorm->forcecompleted);
|
||||
|
||||
if ($trackid) {
|
||||
|
@ -53,13 +53,10 @@ class provider implements
|
||||
* @return collection A listing of user data stored through this system.
|
||||
*/
|
||||
public static function get_metadata(collection $collection) : collection {
|
||||
$collection->add_database_table('scorm_scoes_track', [
|
||||
$collection->add_database_table('scorm_attempt', [
|
||||
'userid' => 'privacy:metadata:userid',
|
||||
'attempt' => 'privacy:metadata:attempt',
|
||||
'element' => 'privacy:metadata:scoes_track:element',
|
||||
'value' => 'privacy:metadata:scoes_track:value',
|
||||
'timemodified' => 'privacy:metadata:timemodified'
|
||||
], 'privacy:metadata:scorm_scoes_track');
|
||||
], 'privacy:metadata:scorm_attempt');
|
||||
|
||||
$collection->add_database_table('scorm_aicc_session', [
|
||||
'userid' => 'privacy:metadata:userid',
|
||||
@ -100,7 +97,7 @@ class provider implements
|
||||
|
||||
$params = ['modlevel' => CONTEXT_MODULE, 'userid' => $userid];
|
||||
$contextlist = new contextlist();
|
||||
$contextlist->add_from_sql(sprintf($sql, 'scorm_scoes_track'), $params);
|
||||
$contextlist->add_from_sql(sprintf($sql, 'scorm_attempt'), $params);
|
||||
$contextlist->add_from_sql(sprintf($sql, 'scorm_aicc_session'), $params);
|
||||
|
||||
return $contextlist;
|
||||
@ -132,7 +129,7 @@ class provider implements
|
||||
|
||||
$params = ['modlevel' => CONTEXT_MODULE, 'contextid' => $context->id];
|
||||
|
||||
$userlist->add_from_sql('userid', sprintf($sql, 'scorm_scoes_track'), $params);
|
||||
$userlist->add_from_sql('userid', sprintf($sql, 'scorm_attempt'), $params);
|
||||
$userlist->add_from_sql('userid', sprintf($sql, 'scorm_aicc_session'), $params);
|
||||
}
|
||||
|
||||
@ -168,19 +165,21 @@ class provider implements
|
||||
|
||||
// Get scoes_track data.
|
||||
list($insql, $inparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
|
||||
$sql = "SELECT ss.id,
|
||||
ss.attempt,
|
||||
ss.element,
|
||||
ss.value,
|
||||
ss.timemodified,
|
||||
$sql = "SELECT v.id,
|
||||
a.attempt,
|
||||
e.element,
|
||||
v.value,
|
||||
v.timemodified,
|
||||
ctx.id as contextid
|
||||
FROM {scorm_scoes_track} ss
|
||||
FROM {scorm_attempt} a
|
||||
JOIN {scorm_scoes_value} v ON a.id = v.attemptid
|
||||
JOIN {scorm_element} e on e.id = v.elementid
|
||||
JOIN {course_modules} cm
|
||||
ON cm.instance = ss.scormid
|
||||
ON cm.instance = a.scormid
|
||||
JOIN {context} ctx
|
||||
ON ctx.instanceid = cm.id
|
||||
WHERE ctx.id $insql
|
||||
AND ss.userid = :userid";
|
||||
AND a.userid = :userid";
|
||||
$params = array_merge($inparams, ['userid' => $userid]);
|
||||
|
||||
$alldata = [];
|
||||
@ -280,8 +279,9 @@ class provider implements
|
||||
WHERE cm.id = :cmid";
|
||||
$params = ['cmid' => $context->instanceid];
|
||||
|
||||
static::delete_data('scorm_scoes_track', $sql, $params);
|
||||
static::delete_data('scorm_aicc_session', $sql, $params);
|
||||
$coursemodule = get_coursemodule_from_id('scorm', $context->instanceid);
|
||||
scorm_delete_tracks($coursemodule->instance);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -319,8 +319,13 @@ class provider implements
|
||||
AND ctx.id $insql";
|
||||
$params = array_merge($inparams, ['userid' => $userid]);
|
||||
|
||||
static::delete_data('scorm_scoes_track', $sql, $params);
|
||||
static::delete_data('scorm_aicc_session', $sql, $params);
|
||||
foreach ($contextlist->get_contexts() as $context) {
|
||||
if ($context->contextlevel == CONTEXT_MODULE) {
|
||||
$coursemodule = get_coursemodule_from_id('scorm', $context->instanceid);
|
||||
scorm_delete_tracks($coursemodule->instance, null, $userid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -353,8 +358,11 @@ class provider implements
|
||||
AND ss.userid $insql";
|
||||
$params = array_merge($inparams, ['contextid' => $context->id]);
|
||||
|
||||
static::delete_data('scorm_scoes_track', $sql, $params);
|
||||
static::delete_data('scorm_aicc_session', $sql, $params);
|
||||
$coursemodule = get_coursemodule_from_id('scorm', $context->instanceid);
|
||||
foreach ($userlist->get_userids() as $userid) {
|
||||
scorm_delete_tracks($coursemodule->instance, null, $userid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,14 +55,20 @@ if (confirm_sesskey() && (!empty($scoid))) {
|
||||
$request = null;
|
||||
if (has_capability('mod/scorm:savetrack', context_module::instance($cm->id))) {
|
||||
// Preload all current tracking data.
|
||||
$trackdata = $DB->get_records('scorm_scoes_track', array('userid' => $USER->id, 'scormid' => $scorm->id, 'scoid' => $scoid,
|
||||
'attempt' => $attempt), '', 'element, id, value, timemodified');
|
||||
$sql = "SELECT e.element, v.value, v.timemodified, v.id as valueid
|
||||
FROM {scorm_scoes_value} v
|
||||
JOIN {scorm_attempt} a ON a.id = v.attemptid
|
||||
JOIN {scorm_element} e on e.id = v.elementid
|
||||
WHERE a.scormid = :scormid AND a.userid = :userid AND v.scoid = :scoid AND a.attempt = :attempt";
|
||||
$trackdata = $DB->get_records_sql($sql, ['userid' => $USER->id, 'scormid' => $scorm->id,
|
||||
'scoid' => $scoid, 'attempt' => $attempt]);
|
||||
$attemptobject = scorm_get_attempt($USER->id, $scorm->id, $attempt);
|
||||
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,
|
||||
$trackdata) && $result;
|
||||
$result = scorm_insert_track($USER->id, $scorm->id, $scoid, $attemptobject, $element, $value,
|
||||
$scorm->forcecompleted, $trackdata) && $result;
|
||||
}
|
||||
if (substr($element, 0, 15) == 'adl.nav.request') {
|
||||
// SCORM 2004 Sequencing Request.
|
||||
|
@ -374,8 +374,8 @@ function scorm_parse_aicc(&$scorm) {
|
||||
}
|
||||
if (!empty($oldscoes)) {
|
||||
foreach ($oldscoes as $oldsco) {
|
||||
$DB->delete_records('scorm_scoes', array('id' => $oldsco->id));
|
||||
$DB->delete_records('scorm_scoes_track', array('scoid' => $oldsco->id));
|
||||
scorm_delete_tracks($scorm->id, $oldsco->id);
|
||||
$DB->delete_records('scorm_scoes', ['id' => $oldsco->id]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -461,8 +461,8 @@ function scorm_aicc_generate_simple_sco($scorm) {
|
||||
}
|
||||
// Get rid of old ones.
|
||||
foreach ($scos as $oldsco) {
|
||||
$DB->delete_records('scorm_scoes', array('id' => $oldsco->id));
|
||||
$DB->delete_records('scorm_scoes_track', array('scoid' => $oldsco->id));
|
||||
scorm_delete_tracks($scorm->id, $oldsco->id);
|
||||
$DB->delete_records('scorm_scoes', ['id' => $oldsco->id]);
|
||||
}
|
||||
|
||||
$sco->identifier = 'A1';
|
||||
|
@ -81,8 +81,7 @@ function scorm_seq_navigation ($scoid, $userid, $request, $attempt=0) {
|
||||
case 'resumeall_':
|
||||
if (empty($seq->currentactivity)) {
|
||||
// TODO: I think it's suspend instead of suspendedactivity.
|
||||
if ($track = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $scoid, 'userid' => $userid, 'element' => 'suspendedactivity'))) {
|
||||
if (scorm_get_sco_value($scoid, $userid, 'suspendedactivity')) {
|
||||
|
||||
$seq->navigation = true;
|
||||
$seq->sequencing = 'resumeall';
|
||||
@ -323,11 +322,8 @@ function scorm_seq_end_attempt($sco, $userid, $seq) {
|
||||
if (!scorm_seq_is('suspended', $sco->id, $userid)) {
|
||||
if (!isset($sco->completionsetbycontent) || ($sco->completionsetbycontent == 0)) {
|
||||
if (!scorm_seq_is('attemptprogressstatus', $sco->id, $userid, $seq->attempt)) {
|
||||
$incomplete = $DB->get_field('scorm_scoes_track', 'value',
|
||||
array('scoid' => $sco->id,
|
||||
'userid' => $userid,
|
||||
'element' => 'cmi.completion_status'));
|
||||
if ($incomplete != 'incomplete') {
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'cmi.completion_status');
|
||||
if ($r->value != 'incomplete') {
|
||||
scorm_seq_set('attemptprogressstatus', $sco->id, $userid, $seq->attempt);
|
||||
scorm_seq_set('attemptcompletionstatus', $sco->id, $userid, $seq->attempt);
|
||||
}
|
||||
@ -366,12 +362,9 @@ function scorm_seq_end_attempt($sco, $userid, $seq) {
|
||||
}
|
||||
|
||||
function scorm_seq_is($what, $scoid, $userid, $attempt=0) {
|
||||
global $DB;
|
||||
|
||||
// Check if passed activity $what is active.
|
||||
$active = false;
|
||||
if ($track = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $scoid, 'userid' => $userid, 'attempt' => $attempt, 'element' => $what))) {
|
||||
if (scorm_get_sco_value($scoid, $userid, $what, $attempt)) {
|
||||
$active = true;
|
||||
}
|
||||
return $active;
|
||||
@ -384,8 +377,11 @@ function scorm_seq_set($what, $scoid, $userid, $attempt=0, $value='true') {
|
||||
|
||||
// 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));
|
||||
$params = ['userid' => $userid, 'scormid' => $sco->scorm, 'attempt' => $attempt, 'element' => $what];
|
||||
$sql = "WHERE scoid = :scoid AND attemptid = :attemptid AND elementid = (SELECT id
|
||||
FROM {scorm_element}
|
||||
WHERE element = :element)";
|
||||
$DB->delete_records_select('scorm_scoes_value', $sql, $params);
|
||||
} else {
|
||||
scorm_insert_track($userid, $sco->scorm, $sco->id, $attempt, $what, $value);
|
||||
}
|
||||
@ -425,11 +421,9 @@ function scorm_evaluate_condition ($rollupruleconds, $sco, $userid) {
|
||||
}
|
||||
switch ($condition['condition']) {
|
||||
case 'satisfied':
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'objectivesatisfiedstatus'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'objectivesatisfiedstatus');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'objectiveprogressstatus'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'objectiveprogressstatus');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
$res = true;
|
||||
}
|
||||
@ -437,43 +431,37 @@ function scorm_evaluate_condition ($rollupruleconds, $sco, $userid) {
|
||||
break;
|
||||
|
||||
case 'objectiveStatusKnown':
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'objectiveprogressstatus'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'objectiveprogressstatus');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
$res = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'notobjectiveStatusKnown':
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'objectiveprogressstatus'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'objectiveprogressstatus');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
$res = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'objectiveMeasureKnown':
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'objectivemeasurestatus'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'objectivemeasurestatus');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
$res = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'notobjectiveMeasureKnown':
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'objectivemeasurestatus'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'objectivemeasurestatus');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
$res = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'completed':
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'attemptcompletionstatus'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'attemptcompletionstatus');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'attemptprogressstatus'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'attemptprogressstatus');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
$res = true;
|
||||
}
|
||||
@ -481,30 +469,29 @@ function scorm_evaluate_condition ($rollupruleconds, $sco, $userid) {
|
||||
break;
|
||||
|
||||
case 'attempted':
|
||||
$attempt = $DB->get_field('scorm_scoes_track', 'attempt',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'x.start.time'));
|
||||
if ($checknot && $attempt > 0) {
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'x.start.time');
|
||||
if ($checknot && $r->attempt > 0) {
|
||||
$res = true;
|
||||
} else if (!$checknot && $attempt <= 0) {
|
||||
} else if (!$checknot && $r->attempt <= 0) {
|
||||
$res = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'attemptLimitExceeded':
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'activityprogressstatus'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'activityprogressstatus');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid,
|
||||
'element' => 'limitconditionattemptlimitcontrol'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'limitconditionattemptlimitcontrol');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
if ($r = $DB->get_field('scorm_scoes_track', 'attempt', array('scoid' => $sco->id, 'userid' => $userid)) &&
|
||||
$r2 = $DB->get_record('scorm_scoes_track', array('scoid' => $sco->id, 'userid' => $userid,
|
||||
'element' => 'limitconditionattemptlimit')) ) {
|
||||
|
||||
if ($checknot && ($r->value >= $r2->value)) {
|
||||
$sql = "SELECT max(attempt) as attempt
|
||||
FROM {scorm_attempt} a
|
||||
JOIN {scorm_scoes_value} v on v.attemptid = a.id
|
||||
WHERE v.scoid = :scoid AND a.userid = :userid";
|
||||
$r2 = scorm_get_sco_value($sco->id, $userid, 'limitconditionattemptlimit');
|
||||
$attempts = $DB->get_field_sql($sql, ['scoid' => $sco->id, 'userid' => $userid]);
|
||||
if (!empty($attempts) && !empty($r2)) {
|
||||
if ($checknot && ($attempts >= $r2->value)) {
|
||||
$res = true;
|
||||
} else if (!$checknot && ($r->value < $r2->value)) {
|
||||
} else if (!$checknot && ($attempts < $r2->value)) {
|
||||
$res = true;
|
||||
}
|
||||
}
|
||||
@ -513,11 +500,9 @@ function scorm_evaluate_condition ($rollupruleconds, $sco, $userid) {
|
||||
break;
|
||||
|
||||
case 'activityProgressKnown':
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'activityprogressstatus'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'activityprogressstatus');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'attemptprogressstatus'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'attemptprogressstatus');
|
||||
if ((!isset($r->value) && !$checknot) || (isset($r->value) && ($r->value == $checknot))) {
|
||||
$res = true;
|
||||
}
|
||||
@ -558,48 +543,42 @@ function scorm_limit_cond_check ($activity, $userid) {
|
||||
}
|
||||
|
||||
if (!isset($activity->limitcontrol) || ($activity->limitcontrol == 1)) {
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $activity->id, 'userid' => $userid, 'element' => 'activityattemptcount'));
|
||||
$r = scorm_get_sco_value($activity->id, $userid, 'activityattemptcount');
|
||||
if (scorm_seq_is('activityprogressstatus', $activity->id, $userid) && ($r->value >= $activity->limitattempt)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($activity->limitabsdurcontrol) || ($activity->limitabsdurcontrol == 1)) {
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $activity->id, 'userid' => $userid, 'element' => 'activityabsoluteduration'));
|
||||
$r = scorm_get_sco_value($activity->id, $userid, 'activityabsoluteduration');
|
||||
if (scorm_seq_is('activityprogressstatus', $activity->id, $userid) && ($r->value >= $activity->limitabsduration)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($activity->limitexpdurcontrol) || ($activity->limitexpdurcontrol == 1)) {
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $activity->id, 'userid' => $userid, 'element' => 'activityexperiencedduration'));
|
||||
$r = scorm_get_sco_value($activity->id, $userid, 'activityexperiencedduration');
|
||||
if (scorm_seq_is('activityprogressstatus', $activity->id, $userid) && ($r->value >= $activity->limitexpduration)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($activity->limitattabsdurcontrol) || ($activity->limitattabsdurcontrol == 1)) {
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $activity->id, 'userid' => $userid, 'element' => 'attemptabsoluteduration'));
|
||||
$r = scorm_get_sco_value($activity->id, $userid, 'attemptabsoluteduration');
|
||||
if (scorm_seq_is('activityprogressstatus', $activity->id, $userid) && ($r->value >= $activity->limitattabsduration)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($activity->limitattexpdurcontrol) || ($activity->limitattexpdurcontrol == 1)) {
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $activity->id, 'userid' => $userid, 'element' => 'attemptexperiencedduration'));
|
||||
$r = scorm_get_sco_value($activity->id, $userid, 'attemptexperiencedduration');
|
||||
if (scorm_seq_is('activityprogressstatus', $activity->id, $userid) && ($r->value >= $activity->limitattexpduration)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($activity->limitbegincontrol) || ($activity->limitbegincontrol == 1)) {
|
||||
$r = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $activity->id, 'userid' => $userid, 'element' => 'begintime'));
|
||||
$r = scorm_get_sco_value($activity->id, $userid, 'begintime');
|
||||
if (isset($activity->limitbegintime) && time() >= $activity->limitbegintime) {
|
||||
return true;
|
||||
}
|
||||
@ -711,8 +690,7 @@ function scorm_seq_measure_rollup($sco, $userid, $attempt = 0) {
|
||||
$child = scorm_get_sco($child->id);
|
||||
$countedmeasures = $countedmeasures + ($child->measureweight);
|
||||
if (!scorm_seq_is('objectivemeasurestatus', $sco->id, $userid, $attempt)) {
|
||||
$normalizedmeasure = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $child->id, 'userid' => $userid, 'element' => 'objectivenormalizedmeasure'));
|
||||
$normalizedmeasure = scorm_get_sco_value($child->id, $userid, 'objectivenormalizedmeasure');
|
||||
$totalmeasure = $totalmeasure + (($normalizedmeasure->value) * ($child->measureweight));
|
||||
$valid = true;
|
||||
}
|
||||
@ -795,9 +773,7 @@ function scorm_seq_objective_rollup_measure($sco, $userid, $attempt = 0) {
|
||||
} else {
|
||||
$isactive = false;
|
||||
}
|
||||
|
||||
$normalizedmeasure = $DB->get_record('scorm_scoes_track',
|
||||
array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'objectivenormalizedmeasure'));
|
||||
$normalizedmeasure = scorm_get_sco_value($sco->id, $userid, 'objectivenormalizedmeasure');
|
||||
|
||||
$sco = scorm_get_sco ($sco->id);
|
||||
|
||||
@ -891,8 +867,6 @@ function scorm_seq_rollup_rule_check ($sco, $userid, $action) {
|
||||
foreach ($rolluprules as $rolluprule) {
|
||||
foreach ($children as $child) {
|
||||
|
||||
/*$tracked = $DB->get_records('scorm_scoes_track', array('scoid'=>$child->id, 'userid'=>$userid));
|
||||
if ($tracked && $tracked->attemp != 0) {*/
|
||||
$child = scorm_get_sco ($child);
|
||||
if (!isset($child->tracked) || ($child->tracked == 1)) {
|
||||
if (scorm_seq_check_child ($child, $action, $userid)) {
|
||||
|
@ -709,15 +709,15 @@ function scorm_parse_scorm(&$scorm, $manifest) {
|
||||
}
|
||||
if (!empty($olditems)) {
|
||||
foreach ($olditems as $olditem) {
|
||||
$DB->delete_records('scorm_scoes', array('id' => $olditem->id));
|
||||
$DB->delete_records('scorm_scoes_data', array('scoid' => $olditem->id));
|
||||
$DB->delete_records('scorm_scoes_track', array('scoid' => $olditem->id));
|
||||
$DB->delete_records('scorm_seq_objective', array('scoid' => $olditem->id));
|
||||
$DB->delete_records('scorm_seq_mapinfo', array('scoid' => $olditem->id));
|
||||
$DB->delete_records('scorm_seq_ruleconds', array('scoid' => $olditem->id));
|
||||
$DB->delete_records('scorm_seq_rulecond', array('scoid' => $olditem->id));
|
||||
$DB->delete_records('scorm_seq_rolluprule', array('scoid' => $olditem->id));
|
||||
$DB->delete_records('scorm_seq_rolluprulecond', array('scoid' => $olditem->id));
|
||||
$DB->delete_records('scorm_scoes', ['id' => $olditem->id]);
|
||||
$DB->delete_records('scorm_scoes_data', ['scoid' => $olditem->id]);
|
||||
scorm_delete_tracks($scorm->id, $olditem->id);
|
||||
$DB->delete_records('scorm_seq_objective', ['scoid' => $olditem->id]);
|
||||
$DB->delete_records('scorm_seq_mapinfo', ['scoid' => $olditem->id]);
|
||||
$DB->delete_records('scorm_seq_ruleconds', ['scoid' => $olditem->id]);
|
||||
$DB->delete_records('scorm_seq_rulecond', ['scoid' => $olditem->id]);
|
||||
$DB->delete_records('scorm_seq_rolluprule', ['scoid' => $olditem->id]);
|
||||
$DB->delete_records('scorm_seq_rolluprulecond', ['scoid' => $olditem->id]);
|
||||
}
|
||||
}
|
||||
if (empty($scoes->version)) {
|
||||
|
@ -119,7 +119,7 @@ function scorm_seq_check_child ($sco, $action, $userid) {
|
||||
|
||||
$included = false;
|
||||
$sco = scorm_get_sco($sco->id);
|
||||
$r = $DB->get_record('scorm_scoes_track', array('scoid' => $sco->id, 'userid' => $userid, 'element' => 'activityattemptcount'));
|
||||
$r = scorm_get_sco_value($sco->id, $userid, 'activityattemptcount');
|
||||
if ($action == 'satisfied' || $action == 'notsatisfied') {
|
||||
if (!$sco->rollupobjectivesatisfied) {
|
||||
$included = true;
|
||||
@ -262,7 +262,7 @@ function scorm_seq_resume_all_sequencing($scoid, $userid, $seq) {
|
||||
$seq->exception = 'SB.2.6-1';
|
||||
return $seq;
|
||||
}
|
||||
$track = $DB->get_record('scorm_scoes_track', array('scoid' => $scoid, 'userid' => $userid, 'element' => 'suspendedactivity'));
|
||||
$track = scorm_get_sco_value($scoid, $userid, 'suspendedactivity');
|
||||
if (!$track) {
|
||||
$seq->delivery = null;
|
||||
$seq->exception = 'SB.2.6-2';
|
||||
@ -752,13 +752,12 @@ function scorm_content_delivery_environment($seq, $userid) {
|
||||
$seq->exception = 'DB.2-1';
|
||||
return $seq;
|
||||
}
|
||||
$track = $DB->get_record('scorm_scoes_track', array('scoid' => $act->id,
|
||||
'userid' => $userid,
|
||||
'element' => 'suspendedactivity'));
|
||||
$track = scorm_get_sco_value($act->id, $userid, 'suspendedactivity');
|
||||
if ($track != null) {
|
||||
$seq = scorm_clear_suspended_activity($seq->delivery, $seq, $userid);
|
||||
|
||||
}
|
||||
$attemptobject = scorm_get_attempt($userid, $track->scormid, 0);
|
||||
$seq = scorm_terminate_descendent_attempts ($seq->delivery, $userid, $seq);
|
||||
$ancestors = scorm_get_ancestors($seq->delivery);
|
||||
$arrpath = array_reverse($ancestors);
|
||||
@ -767,24 +766,32 @@ function scorm_content_delivery_environment($seq, $userid) {
|
||||
if (!scorm_seq_is('active', $activity->id, $userid)) {
|
||||
if (!isset($activity->tracked) || ($activity->tracked == 1)) {
|
||||
if (!scorm_seq_is('suspended', $activity->id, $userid)) {
|
||||
$r = $DB->get_record('scorm_scoes_track', array('scoid' => $activity->id,
|
||||
'userid' => $userid,
|
||||
'element' => 'activityattemptcount'));
|
||||
$r->value = ($r->value) + 1;
|
||||
$DB->update_record('scorm_scoes_track', $r);
|
||||
$r = scorm_get_sco_value($activity->id, $userid, 'activityattemptcount');
|
||||
$value = new stdClass();
|
||||
$value->id = $r->valueid;
|
||||
$value->value = ($r->value) + 1;
|
||||
$DB->update_record('scorm_scoes_value', $value);
|
||||
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_insert_track($userid, $activity->scorm, $activity->id, $attemptobject,
|
||||
'objectiveprogressstatus', 'false');
|
||||
scorm_insert_track($userid, $activity->scorm, $activity->id, $attemptobject,
|
||||
'objectivesatisfiedstatus', 'false');
|
||||
scorm_insert_track($userid, $activity->scorm, $activity->id, $attemptobject,
|
||||
'objectivemeasurestatus', 'false');
|
||||
scorm_insert_track($userid, $activity->scorm, $activity->id, $attemptobject,
|
||||
'objectivenormalizedmeasure', 0.0);
|
||||
scorm_insert_track($userid, $activity->scorm, $activity->id, $attemptobject,
|
||||
'attemptprogressstatus', 'false');
|
||||
scorm_insert_track($userid, $activity->scorm, $activity->id, $attemptobject,
|
||||
'attemptcompletionstatus', 'false');
|
||||
scorm_insert_track($userid, $activity->scorm, $activity->id, $attemptobject,
|
||||
'attemptabsoluteduration', 0.0);
|
||||
scorm_insert_track($userid, $activity->scorm, $activity->id, $attemptobject,
|
||||
'attemptexperiencedduration', 0.0);
|
||||
scorm_insert_track($userid, $activity->scorm, $activity->id, $attemptobject,
|
||||
'attemptcompletionamount', 0.0);
|
||||
}
|
||||
}
|
||||
scorm_seq_set('active', $activity->id, $userid, 'true');
|
||||
@ -793,26 +800,13 @@ function scorm_content_delivery_environment($seq, $userid) {
|
||||
$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 = $DB->get_record('scorm_scoes_track', array('scoid' => $activity->id,
|
||||
'userid' => $userid,
|
||||
'element' => 'attemptabsoluteduration'));
|
||||
$atexpdur = $DB->get_record('scorm_scoes_track', array('scoid' => $activity->id,
|
||||
'userid' => $userid,
|
||||
'element' => 'attemptexperiencedduration'));
|
||||
}
|
||||
return $seq;
|
||||
}
|
||||
|
||||
function scorm_clear_suspended_activity($act, $seq, $userid) {
|
||||
global $DB;
|
||||
$currentact = $seq->currentactivity;
|
||||
$track = $DB->get_record('scorm_scoes_track', array('scoid' => $currentact->id,
|
||||
'userid' => $userid,
|
||||
'element' => 'suspendedactivity'));
|
||||
$track = scorm_get_sco_value($currentact->id, $userid, 'suspendedactivity');
|
||||
if ($track != null) {
|
||||
$ancestors = scorm_get_ancestors($act);
|
||||
$commonpos = scorm_find_common_ancestor($ancestors, $currentact);
|
||||
@ -849,9 +843,7 @@ function scorm_select_children_process($scoid, $userid) {
|
||||
$sco = scorm_get_sco($scoid);
|
||||
if (!scorm_is_leaf($sco)) {
|
||||
if (!scorm_seq_is('suspended', $scoid, $userid) && !scorm_seq_is('active', $scoid, $userid)) {
|
||||
$r = $DB->get_record('scorm_scoes_track', array('scoid' => $scoid,
|
||||
'userid' => $userid,
|
||||
'element' => 'selectiontiming'));
|
||||
$r = scorm_get_sco_value($scoid, $userid, 'selectiontiming');
|
||||
|
||||
switch ($r->value) {
|
||||
case 'oneachnewattempt':
|
||||
@ -862,9 +854,7 @@ function scorm_select_children_process($scoid, $userid) {
|
||||
if (!scorm_seq_is('activityprogressstatus', $scoid, $userid)) {
|
||||
if (scorm_seq_is('selectioncountsstatus', $scoid, $userid)) {
|
||||
$childlist = '';
|
||||
$res = $DB->get_record('scorm_scoes_track', array('scoid' => $scoid,
|
||||
'userid' => $userid,
|
||||
'element' => 'selectioncount'));
|
||||
$res = scorm_get_sco_value($scoid, $userid, 'selectioncount');
|
||||
$i = ($res->value) - 1;
|
||||
$children = scorm_get_children($sco);
|
||||
|
||||
@ -892,9 +882,7 @@ function scorm_randomize_children_process($scoid, $userid) {
|
||||
$sco = scorm_get_sco($scoid);
|
||||
if (!scorm_is_leaf($sco)) {
|
||||
if (!scorm_seq_is('suspended', $scoid, $userid) && !scorm_seq_is('active', $scoid, $userid)) {
|
||||
$r = $DB->get_record('scorm_scoes_track', array('scoid' => $scoid,
|
||||
'userid' => $userid,
|
||||
'element' => 'randomizationtiming'));
|
||||
$r = scorm_get_sco_value($scoid, $userid, 'randomizationtiming');
|
||||
|
||||
switch ($r->value) {
|
||||
case 'never':
|
||||
|
33
mod/scorm/db/caches.php
Normal file
33
mod/scorm/db/caches.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* SCORM cache definition.
|
||||
*
|
||||
* @package mod_scorm
|
||||
* @copyright 2023 Catalyst IT Ltd
|
||||
* @author Dan Marsden <dan@danmarsden.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$definitions = [
|
||||
'elements' => [
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'datasource' => '\mod_scorm\cache\elements',
|
||||
]
|
||||
];
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="mod/scorm/db" VERSION="20220127" COMMENT="XMLDB file for Moodle mod/scorm"
|
||||
<XMLDB PATH="mod/scorm/db" VERSION="20230406" COMMENT="XMLDB file for Moodle mod/scorm"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@ -85,27 +85,6 @@
|
||||
<KEY NAME="scorm_scoes_data_scoid" TYPE="foreign" FIELDS="scoid" REFTABLE="scorm_scoes" REFFIELDS="id" COMMENT="The relative sco"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="scorm_scoes_track" COMMENT="to track SCOes">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="scormid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="scoid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="attempt" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
|
||||
<FIELD NAME="element" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="value" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="scormid" TYPE="foreign" FIELDS="scormid" REFTABLE="scorm" REFFIELDS="id"/>
|
||||
<KEY NAME="scoid" TYPE="foreign" FIELDS="scoid" REFTABLE="scorm_scoes" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="userid-scormid-scoid-attempt-element" UNIQUE="true" FIELDS="userid, scormid, scoid, attempt, element"/>
|
||||
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="scorm_seq_objective" COMMENT="SCORM2004 objective description">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
@ -222,5 +201,46 @@
|
||||
<KEY NAME="userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="scorm_attempt" COMMENT="List of SCORM attempts made by user.">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="scormid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The id of the scorm table"/>
|
||||
<FIELD NAME="attempt" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="The attempt number"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="user" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id" COMMENT="The id field of the user table"/>
|
||||
<KEY NAME="scorm" TYPE="foreign" FIELDS="scormid" REFTABLE="scorm" REFFIELDS="id" COMMENT="The id of the scormtable"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="scorm_element" COMMENT="List of scorm elements.">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="element" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="Name of SCORM element"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="element" UNIQUE="true" FIELDS="element"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="scorm_scoes_value" COMMENT="Values passed from SCORM package">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="scoid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The id of the scorm_scoes table"/>
|
||||
<FIELD NAME="attemptid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="id from scorm_attempt"/>
|
||||
<FIELD NAME="elementid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="id from scorm_element"/>
|
||||
<FIELD NAME="value" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Value passed from SCORM package"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Time value last changed."/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="scoe" TYPE="foreign" FIELDS="scoid" REFTABLE="scorm_scoes" REFFIELDS="id" COMMENT="The id of the scorm_scoes table"/>
|
||||
<KEY NAME="attempt" TYPE="foreign" FIELDS="attemptid" REFTABLE="scorm_attempt" REFFIELDS="id" COMMENT="id from scorm_attempt"/>
|
||||
<KEY NAME="element" TYPE="foreign" FIELDS="elementid" REFTABLE="scorm_element" REFFIELDS="id" COMMENT="id from scorm_element"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
</XMLDB>
|
||||
|
@ -30,7 +30,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @return bool
|
||||
*/
|
||||
function xmldb_scorm_upgrade($oldversion) {
|
||||
global $DB;
|
||||
global $DB, $OUTPUT;
|
||||
|
||||
$dbman = $DB->get_manager();
|
||||
|
||||
@ -55,5 +55,118 @@ function xmldb_scorm_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// New table structure for scorm_scoes_track.
|
||||
if ($oldversion < 2023042401) {
|
||||
// Define table scorm_attempt to be created.
|
||||
$table = new xmldb_table('scorm_attempt');
|
||||
|
||||
// Adding fields to table scorm_attempt.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('scormid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('attempt', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '1');
|
||||
|
||||
// Adding keys to table scorm_attempt.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
|
||||
$table->add_key('user', XMLDB_KEY_FOREIGN, ['userid'], 'user', ['id']);
|
||||
$table->add_key('scorm', XMLDB_KEY_FOREIGN, ['scormid'], 'scorm', ['id']);
|
||||
|
||||
// Conditionally launch create table for scorm_attempt.
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// Define table scorm_element to be created.
|
||||
$table = new xmldb_table('scorm_element');
|
||||
|
||||
// Adding fields to table scorm_element.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('element', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
|
||||
|
||||
// Adding keys to table scorm_element.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
|
||||
|
||||
// Adding indexes to table scorm_element.
|
||||
$table->add_index('element', XMLDB_INDEX_UNIQUE, ['element']);
|
||||
|
||||
// Conditionally launch create table for scorm_element.
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// Define table scorm_scoes_value to be created.
|
||||
$table = new xmldb_table('scorm_scoes_value');
|
||||
|
||||
// Adding fields to table scorm_scoes_value.
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('scoid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('attemptid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('elementid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('value', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
|
||||
|
||||
// Adding keys to table scorm_scoes_value.
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
|
||||
$table->add_key('scoe', XMLDB_KEY_FOREIGN, ['scoid'], 'scorm_scoes', ['id']);
|
||||
$table->add_key('attempt', XMLDB_KEY_FOREIGN, ['attemptid'], 'scorm_attempt', ['id']);
|
||||
$table->add_key('element', XMLDB_KEY_FOREIGN, ['elementid'], 'scorm_element', ['id']);
|
||||
|
||||
// Conditionally launch create table for scorm_scoes_value.
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
upgrade_mod_savepoint(true, 2023042401, 'scorm');
|
||||
}
|
||||
|
||||
if ($oldversion < 2023042402) {
|
||||
$trans = $DB->start_delegated_transaction();
|
||||
|
||||
// First grab all elements and store those.
|
||||
$sql = "INSERT INTO {scorm_element} (element)
|
||||
SELECT DISTINCT element FROM {scorm_scoes_track}";
|
||||
$DB->execute($sql);
|
||||
|
||||
// Now store all data in the scorm_attempt table.
|
||||
$sql = "INSERT INTO {scorm_attempt} (userid, scormid, attempt)
|
||||
SELECT DISTINCT userid, scormid, attempt FROM {scorm_scoes_track}";
|
||||
$DB->execute($sql);
|
||||
|
||||
$trans->allow_commit();
|
||||
// Scorm savepoint reached.
|
||||
upgrade_mod_savepoint(true, 2023042402, 'scorm');
|
||||
|
||||
}
|
||||
if ($oldversion < 2023042403) {
|
||||
// Now store all translated data in the scorm_scoes_value table.
|
||||
$total = $DB->count_records('scorm_scoes_track');
|
||||
if ($total > 500000) {
|
||||
// This site has a large number of user track records, lets warn that this next part may take some time.
|
||||
$notification = new \core\output\notification(get_string('largetrackupgrade', 'scorm', format_float($total, 0)),
|
||||
\core\output\notification::NOTIFY_WARNING);
|
||||
$notification->set_show_closebutton(false);
|
||||
echo $OUTPUT->render($notification);
|
||||
}
|
||||
|
||||
// We don't need a progress bar - just run the fastest option possible.
|
||||
$sql = "INSERT INTO {scorm_scoes_value} (attemptid, scoid, elementid, value, timemodified)
|
||||
SELECT a.id as attemptid, t.scoid as scoid, e.id as elementid, t.value as value, t.timemodified
|
||||
FROM {scorm_scoes_track} t
|
||||
JOIN {scorm_element} e ON e.element = t.element
|
||||
JOIN {scorm_attempt} a ON (t.userid = a.userid AND t.scormid = a.scormid AND a.attempt = t.attempt)";
|
||||
$DB->execute($sql);
|
||||
|
||||
// Drop old table scorm_scoes_track.
|
||||
$table = new xmldb_table('scorm_scoes_track');
|
||||
|
||||
// Conditionally launch drop table for scorm_scoes_track.
|
||||
if ($dbman->table_exists($table)) {
|
||||
$dbman->drop_table($table);
|
||||
}
|
||||
|
||||
// Scorm savepoint reached.
|
||||
upgrade_mod_savepoint(true, 2023042403, 'scorm');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -54,16 +54,18 @@ function scorm_get_completion_state($course, $cm, $userid, $type) {
|
||||
$tracks = $DB->get_records_sql(
|
||||
"
|
||||
SELECT
|
||||
id,
|
||||
scoid,
|
||||
element,
|
||||
value
|
||||
v.id,
|
||||
v.scoid,
|
||||
e.element,
|
||||
v.value
|
||||
FROM
|
||||
{scorm_scoes_track}
|
||||
{scorm_scoes_value} v
|
||||
JOIN {scorm_attempt} a on a.id = v.attemptid
|
||||
JOIN {scorm_element} e on e.id = v.elementid
|
||||
WHERE
|
||||
scormid = ?
|
||||
AND userid = ?
|
||||
AND element IN
|
||||
a.scormid = ?
|
||||
AND a.userid = ?
|
||||
AND e.element IN
|
||||
(
|
||||
'cmi.core.lesson_status',
|
||||
'cmi.completion_status',
|
||||
|
@ -71,6 +71,7 @@ $string['browse'] = 'Preview';
|
||||
$string['browsed'] = 'Browsed';
|
||||
$string['browsemode'] = 'Preview mode';
|
||||
$string['browserepository'] = 'Browse repository';
|
||||
$string['cachedef_elements'] = 'Element cache';
|
||||
$string['calculatedweight'] = 'Calculated weight';
|
||||
$string['calendarend'] = '{$a} closes';
|
||||
$string['calendarstart'] = '{$a} opens';
|
||||
@ -213,6 +214,7 @@ $string['indicator:socialbreadthdef_help'] = 'The participant has reached this p
|
||||
$string['indicator:socialbreadthdef_link'] = 'Learning_analytics_indicators#Social_breadth';
|
||||
|
||||
$string['interactions'] = 'Interactions';
|
||||
$string['largetrackupgrade'] = 'This next upgrade step may take some time to complete, your site has {$a} SCORM track records that need to be migrated to the new table structure, please be patient as a progress bar is not able to be displayed.';
|
||||
$string['masteryoverride'] = 'Mastery score overrides status';
|
||||
$string['masteryoverride_help'] = 'If enabled and a mastery score is provided, when LMSFinish is called and a raw score has been set, status will be recalculated using the raw score and mastery score and any status provided by the SCORM (including "incomplete") will be overridden.';
|
||||
$string['masteryoverridedesc'] = 'This preference sets the default for the mastery score override setting';
|
||||
@ -354,7 +356,7 @@ $string['privacy:metadata:attempt'] = 'The attempt number';
|
||||
$string['privacy:metadata:scoes_track:element'] = 'The name of the element to be tracked';
|
||||
$string['privacy:metadata:scoes_track:value'] = 'The value of the given element';
|
||||
$string['privacy:metadata:scorm_aicc_session'] = 'The session information of the AICC HACP';
|
||||
$string['privacy:metadata:scorm_scoes_track'] = 'The tracked data of the SCOes belonging to the activity';
|
||||
$string['privacy:metadata:scorm_attempt'] = 'The SCORM attempts made by a user';
|
||||
$string['privacy:metadata:timemodified'] = 'The time when the tracked element was last modified';
|
||||
$string['privacy:metadata:userid'] = 'The ID of the user who accessed the SCORM activity';
|
||||
$string['protectpackagedownloads'] = 'Protect package downloads';
|
||||
|
@ -293,9 +293,7 @@ function scorm_delete_instance($id) {
|
||||
$result = true;
|
||||
|
||||
// Delete any dependent records.
|
||||
if (! $DB->delete_records('scorm_scoes_track', array('scormid' => $scorm->id))) {
|
||||
$result = false;
|
||||
}
|
||||
scorm_delete_tracks($scorm->id);
|
||||
if ($scoes = $DB->get_records('scorm_scoes', array('scorm' => $scorm->id))) {
|
||||
foreach ($scoes as $sco) {
|
||||
if (! $DB->delete_records('scorm_scoes_data', array('scoid' => $sco->id))) {
|
||||
@ -594,31 +592,33 @@ function scorm_get_user_grades($scorm, $userid=0) {
|
||||
|
||||
$grades = array();
|
||||
if (empty($userid)) {
|
||||
$scousers = $DB->get_records_select('scorm_scoes_track', "scormid=? GROUP BY userid",
|
||||
array($scorm->id), "", "userid,null");
|
||||
if ($scousers) {
|
||||
foreach ($scousers as $scouser) {
|
||||
$grades[$scouser->userid] = new stdClass();
|
||||
$grades[$scouser->userid]->id = $scouser->userid;
|
||||
$grades[$scouser->userid]->userid = $scouser->userid;
|
||||
$grades[$scouser->userid]->rawgrade = scorm_grade_user($scorm, $scouser->userid);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$sql = "SELECT DISTINCT userid
|
||||
FROM {scorm_attempt}
|
||||
WHERE scormid = ?";
|
||||
$scousers = $DB->get_recordset_sql($sql, [$scorm->id]);
|
||||
|
||||
foreach ($scousers as $scouser) {
|
||||
$grades[$scouser->userid] = new stdClass();
|
||||
$grades[$scouser->userid]->id = $scouser->userid;
|
||||
$grades[$scouser->userid]->userid = $scouser->userid;
|
||||
$grades[$scouser->userid]->rawgrade = scorm_grade_user($scorm, $scouser->userid);
|
||||
}
|
||||
$scousers->close();
|
||||
} else {
|
||||
$preattempt = $DB->get_records_select('scorm_scoes_track', "scormid=? AND userid=? GROUP BY userid",
|
||||
array($scorm->id, $userid), "", "userid,null");
|
||||
$preattempt = $DB->record_exists('scorm_attempt', ['scormid' => $scorm->id, 'userid' => $userid]);
|
||||
if (!$preattempt) {
|
||||
return false; // No attempt yet.
|
||||
}
|
||||
$grades[$userid] = new stdClass();
|
||||
$grades[$userid]->id = $userid;
|
||||
$grades[$userid]->userid = $userid;
|
||||
$grades[$userid]->id = $userid;
|
||||
$grades[$userid]->userid = $userid;
|
||||
$grades[$userid]->rawgrade = scorm_grade_user($scorm, $userid);
|
||||
}
|
||||
|
||||
if (empty($grades)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $grades;
|
||||
}
|
||||
|
||||
@ -819,30 +819,31 @@ function scorm_reset_gradebook($courseid, $type='') {
|
||||
* @return array status array
|
||||
*/
|
||||
function scorm_reset_userdata($data) {
|
||||
global $CFG, $DB;
|
||||
global $DB;
|
||||
|
||||
$componentstr = get_string('modulenameplural', 'scorm');
|
||||
$status = array();
|
||||
$status = [];
|
||||
|
||||
if (!empty($data->reset_scorm)) {
|
||||
$scormssql = "SELECT s.id
|
||||
FROM {scorm} s
|
||||
WHERE s.course=?";
|
||||
|
||||
$DB->delete_records_select('scorm_scoes_track', "scormid IN ($scormssql)", array($data->courseid));
|
||||
$scorms = $DB->get_recordset('scorm', ['course' => $data->courseid]);
|
||||
foreach ($scorms as $scorm) {
|
||||
scorm_delete_tracks($scorm->id);
|
||||
}
|
||||
$scorms->close();
|
||||
|
||||
// Remove all grades from gradebook.
|
||||
if (empty($data->reset_gradebook_grades)) {
|
||||
scorm_reset_gradebook($data->courseid);
|
||||
}
|
||||
|
||||
$status[] = array('component' => $componentstr, 'item' => get_string('deleteallattempts', 'scorm'), 'error' => false);
|
||||
$status[] = ['component' => $componentstr, 'item' => get_string('deleteallattempts', 'scorm'), 'error' => false];
|
||||
}
|
||||
|
||||
// Any changes to the list of dates that needs to be rolled should be same during course restore and course reset.
|
||||
// See MDL-9367.
|
||||
shift_course_mod_dates('scorm', array('timeopen', 'timeclose'), $data->timeshift, $data->courseid);
|
||||
$status[] = array('component' => $componentstr, 'item' => get_string('datechanged'), 'error' => false);
|
||||
$status[] = ['component' => $componentstr, 'item' => get_string('datechanged'), 'error' => false];
|
||||
|
||||
return $status;
|
||||
}
|
||||
@ -1296,7 +1297,7 @@ function scorm_check_mode($scorm, &$newattempt, &$attempt, $userid, &$mode) {
|
||||
$mode = 'normal';
|
||||
if ($attempt == 1) {
|
||||
// Check if the user has any existing data or if this is really the first attempt.
|
||||
$exists = $DB->record_exists('scorm_scoes_track', array('userid' => $userid, 'scormid' => $scorm->id));
|
||||
$exists = $DB->record_exists('scorm_attempt', ['userid' => $userid, 'scormid' => $scorm->id]);
|
||||
if (!$exists) {
|
||||
// No records yet - Attempt should == 1.
|
||||
return;
|
||||
@ -1326,12 +1327,17 @@ function scorm_check_mode($scorm, &$newattempt, &$attempt, $userid, &$mode) {
|
||||
}
|
||||
$completionelement = $completionelements[$scormversion];
|
||||
|
||||
$sql = "SELECT sc.id, t.value
|
||||
$sql = "SELECT sc.id, sub.value
|
||||
FROM {scorm_scoes} sc
|
||||
LEFT JOIN {scorm_scoes_track} t ON sc.scorm = t.scormid AND sc.id = t.scoid
|
||||
AND t.element = ? AND t.userid = ? AND t.attempt = ?
|
||||
WHERE sc.scormtype = 'sco' AND sc.scorm = ?";
|
||||
$tracks = $DB->get_recordset_sql($sql, array($completionelement, $userid, $attempt, $scorm->id));
|
||||
LEFT JOIN (SELECT v.scoid, v.value
|
||||
FROM {scorm_attempt} a
|
||||
JOIN {scorm_scoes_value} v ON a.id = v.attemptid
|
||||
JOIN {scorm_element} e on e.id = v.elementid AND e.element = :element
|
||||
WHERE a.userid = :userid AND a.attempt = :attempt AND a.scormid = :scormid) sub ON sub.scoid = sc.id
|
||||
WHERE sc.scormtype = 'sco' AND sc.scorm = :scormid2";
|
||||
$tracks = $DB->get_recordset_sql($sql, ['userid' => $userid, 'attempt' => $attempt,
|
||||
'element' => $completionelement, 'scormid' => $scorm->id,
|
||||
'scormid2' => $scorm->id]);
|
||||
|
||||
foreach ($tracks as $track) {
|
||||
if (($track->value == 'completed') || ($track->value == 'passed') || ($track->value == 'failed')) {
|
||||
@ -1410,9 +1416,12 @@ function scorm_check_updates_since(cm_info $cm, $from, $filter = array()) {
|
||||
$updates = course_check_module_updates_since($cm, $from, array('package'), $filter);
|
||||
|
||||
$updates->tracks = (object) array('updated' => false);
|
||||
$select = 'scormid = ? AND userid = ? AND timemodified > ?';
|
||||
$params = array($scorm->id, $USER->id, $from);
|
||||
$tracks = $DB->get_records_select('scorm_scoes_track', $select, $params, '', 'id');
|
||||
$sql = "SELECT v.id
|
||||
FROM {scorm_scoes_value} v
|
||||
JOIN {scorm_attempt} a ON a.id = v.attemptid
|
||||
WHERE a.scormid = :scormid AND v.timemodified > :timemodified";
|
||||
$params = ['scormid' => $scorm->id, 'timemodified' => $from, 'userid' => $USER->id];
|
||||
$tracks = $DB->get_records_sql($sql ." AND a.userid = :userid", $params);
|
||||
if (!empty($tracks)) {
|
||||
$updates->tracks->updated = true;
|
||||
$updates->tracks->itemids = array_keys($tracks);
|
||||
@ -1420,21 +1429,21 @@ function scorm_check_updates_since(cm_info $cm, $from, $filter = array()) {
|
||||
|
||||
// Now, teachers should see other students updates.
|
||||
if (has_capability('mod/scorm:viewreport', $cm->context)) {
|
||||
$select = 'scormid = ? AND timemodified > ?';
|
||||
$params = array($scorm->id, $from);
|
||||
$params = ['scormid' => $scorm->id, 'timemodified' => $from];
|
||||
|
||||
if (groups_get_activity_groupmode($cm) == SEPARATEGROUPS) {
|
||||
$groupusers = array_keys(groups_get_activity_shared_group_members($cm));
|
||||
if (empty($groupusers)) {
|
||||
return $updates;
|
||||
}
|
||||
list($insql, $inparams) = $DB->get_in_or_equal($groupusers);
|
||||
$select .= ' AND userid ' . $insql;
|
||||
list($insql, $inparams) = $DB->get_in_or_equal($groupusers, SQL_PARAMS_NAMED);
|
||||
$sql .= ' AND userid ' . $insql;
|
||||
$params = array_merge($params, $inparams);
|
||||
}
|
||||
|
||||
$updates->usertracks = (object) array('updated' => false);
|
||||
$tracks = $DB->get_records_select('scorm_scoes_track', $select, $params, '', 'id');
|
||||
|
||||
$tracks = $DB->get_records_sql($sql, $params);
|
||||
if (!empty($tracks)) {
|
||||
$updates->usertracks->updated = true;
|
||||
$updates->usertracks->itemids = array_keys($tracks);
|
||||
|
@ -436,29 +436,46 @@ function scorm_get_scoes($id, $organisation=false) {
|
||||
}
|
||||
}
|
||||
|
||||
function scorm_insert_track($userid, $scormid, $scoid, $attempt, $element, $value, $forcecompleted=false, $trackdata = null) {
|
||||
/**
|
||||
* Insert SCORM track into db.
|
||||
*
|
||||
* @param int $userid The userid
|
||||
* @param int $scormid The id from scorm table
|
||||
* @param int $scoid The scoid
|
||||
* @param int|stdClass $attemptornumber - number of attempt or attempt record from scorm_attempt table.
|
||||
* @param string $element The element being saved
|
||||
* @param string $value The value of the element
|
||||
* @param boolean $forcecompleted Force this sco as completed
|
||||
* @param stdclass $trackdata - existing tracking data
|
||||
* @return int - the id of the record being saved.
|
||||
*/
|
||||
function scorm_insert_track($userid, $scormid, $scoid, $attemptornumber, $element, $value, $forcecompleted=false, $trackdata = null) {
|
||||
global $DB, $CFG;
|
||||
|
||||
if (is_object($attemptornumber)) {
|
||||
$attempt = $attemptornumber;
|
||||
} else {
|
||||
$attempt = scorm_get_attempt($userid, $scormid, $attemptornumber);
|
||||
}
|
||||
|
||||
$id = null;
|
||||
|
||||
if ($forcecompleted) {
|
||||
// TODO - this could be broadened to encompass SCORM 2004 in future.
|
||||
if (($element == 'cmi.core.lesson_status') && ($value == 'incomplete')) {
|
||||
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))) {
|
||||
$track = scorm_get_sco_value($scoid, $userid, 'cmi.core.score.raw', $attempt->attempt);
|
||||
if (!empty($track)) {
|
||||
$value = 'completed';
|
||||
}
|
||||
}
|
||||
if ($element == 'cmi.core.score.raw') {
|
||||
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))) {
|
||||
$tracktest = scorm_get_sco_value($scoid, $userid, 'cmi.core.lesson_status', $attempt->attempt);
|
||||
if (!empty($tracktest)) {
|
||||
if ($tracktest->value == "incomplete") {
|
||||
$tracktest->value = "completed";
|
||||
$DB->update_record('scorm_scoes_track', $tracktest);
|
||||
$v = new stdClass();
|
||||
$v->id = $track->valueid;
|
||||
$v->value = "completed";
|
||||
$DB->update_record('scorm_scoes_value', $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -469,47 +486,40 @@ function scorm_insert_track($userid, $scormid, $scoid, $attempt, $element, $valu
|
||||
if ($value == 'passed') {
|
||||
$objectivesatisfiedstatus = true;
|
||||
}
|
||||
|
||||
if ($track = $DB->get_record('scorm_scoes_track', array('userid' => $userid,
|
||||
'scormid' => $scormid,
|
||||
'scoid' => $scoid,
|
||||
'attempt' => $attempt,
|
||||
'element' => 'objectiveprogressstatus'))) {
|
||||
$track->value = $objectiveprogressstatus;
|
||||
$track->timemodified = time();
|
||||
$DB->update_record('scorm_scoes_track', $track);
|
||||
$id = $track->id;
|
||||
$track = scorm_get_sco_value($scoid, $userid, 'objectiveprogressstatus', $attempt->attempt);
|
||||
if (!empty($track)) {
|
||||
$v = new stdClass();
|
||||
$v->id = $track->valueid;
|
||||
$v->value = $objectiveprogressstatus;
|
||||
$v->timemodified = time();
|
||||
$DB->update_record('scorm_scoes_value', $v);
|
||||
$id = $track->valueid;
|
||||
} else {
|
||||
$track = new stdClass();
|
||||
$track->userid = $userid;
|
||||
$track->scormid = $scormid;
|
||||
$track->scoid = $scoid;
|
||||
$track->attempt = $attempt;
|
||||
$track->element = 'objectiveprogressstatus';
|
||||
$track->attemptid = $attempt->id;
|
||||
$track->elementid = scorm_get_elementid('objectiveprogressstatus');
|
||||
$track->value = $objectiveprogressstatus;
|
||||
$track->timemodified = time();
|
||||
$id = $DB->insert_record('scorm_scoes_track', $track);
|
||||
$id = $DB->insert_record('scorm_scoes_value', $track);
|
||||
}
|
||||
if ($objectivesatisfiedstatus) {
|
||||
if ($track = $DB->get_record('scorm_scoes_track', array('userid' => $userid,
|
||||
'scormid' => $scormid,
|
||||
'scoid' => $scoid,
|
||||
'attempt' => $attempt,
|
||||
'element' => 'objectivesatisfiedstatus'))) {
|
||||
$track->value = $objectivesatisfiedstatus;
|
||||
$track->timemodified = time();
|
||||
$DB->update_record('scorm_scoes_track', $track);
|
||||
$id = $track->id;
|
||||
$track = scorm_get_sco_value($scoid, $userid, 'objectivesatisfiedstatus', $attempt->attempt);
|
||||
if (!empty($track)) {
|
||||
$v = new stdClass();
|
||||
$v->id = $track->valueid;
|
||||
$v->value = $objectivesatisfiedstatus;
|
||||
$v->timemodified = time();
|
||||
$DB->update_record('scorm_scoes_value', $v);
|
||||
$id = $track->valueid;
|
||||
} else {
|
||||
$track = new stdClass();
|
||||
$track->userid = $userid;
|
||||
$track->scormid = $scormid;
|
||||
$track->scoid = $scoid;
|
||||
$track->attempt = $attempt;
|
||||
$track->element = 'objectivesatisfiedstatus';
|
||||
$track->attemptid = $attempt->id;
|
||||
$track->elementid = scorm_get_elementid('objectivesatisfiedstatus');
|
||||
$track->value = $objectivesatisfiedstatus;
|
||||
$track->timemodified = time();
|
||||
$id = $DB->insert_record('scorm_scoes_track', $track);
|
||||
$id = $DB->insert_record('scorm_scoes_value', $track);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -523,31 +533,27 @@ function scorm_insert_track($userid, $scormid, $scoid, $attempt, $element, $valu
|
||||
$track = $trackdata[$element];
|
||||
}
|
||||
} else {
|
||||
$track = $DB->get_record('scorm_scoes_track', array('userid' => $userid,
|
||||
'scormid' => $scormid,
|
||||
'scoid' => $scoid,
|
||||
'attempt' => $attempt,
|
||||
'element' => $element));
|
||||
$track = scorm_get_sco_value($scoid, $userid, $element, $attempt->attempt);
|
||||
}
|
||||
if ($track) {
|
||||
if ($element != 'x.start.time' ) { // Don't update x.start.time - keep the original value.
|
||||
if ($track->value != $value) {
|
||||
$track->value = $value;
|
||||
$track->timemodified = time();
|
||||
$DB->update_record('scorm_scoes_track', $track);
|
||||
$v = new stdClass();
|
||||
$v->id = $track->valueid;
|
||||
$v->value = $value;
|
||||
$v->timemodified = time();
|
||||
$DB->update_record('scorm_scoes_value', $v);
|
||||
}
|
||||
$id = $track->id;
|
||||
$id = $track->valueid;
|
||||
}
|
||||
} else {
|
||||
$track = new stdClass();
|
||||
$track->userid = $userid;
|
||||
$track->scormid = $scormid;
|
||||
$track->scoid = $scoid;
|
||||
$track->attempt = $attempt;
|
||||
$track->element = $element;
|
||||
$track->attemptid = $attempt->id;
|
||||
$track->elementid = scorm_get_elementid($element);
|
||||
$track->value = $value;
|
||||
$track->timemodified = time();
|
||||
$id = $DB->insert_record('scorm_scoes_track', $track);
|
||||
$id = $DB->insert_record('scorm_scoes_value', $track);
|
||||
$track->id = $id;
|
||||
}
|
||||
|
||||
@ -570,7 +576,7 @@ function scorm_insert_track($userid, $scormid, $scoid, $attempt, $element, $valu
|
||||
}
|
||||
$cm = get_coursemodule_from_instance('scorm', $scormid);
|
||||
$data = array(
|
||||
'other' => array('attemptid' => $attempt, 'cmielement' => $element, 'cmivalue' => $track->value),
|
||||
'other' => array('attemptid' => $attempt->id, 'cmielement' => $element, 'cmivalue' => $track->value),
|
||||
'objectid' => $scorm->id,
|
||||
'context' => context_module::instance($cm->id),
|
||||
'relateduserid' => $userid
|
||||
@ -584,13 +590,12 @@ function scorm_insert_track($userid, $scormid, $scoid, $attempt, $element, $valu
|
||||
}
|
||||
// Fix the missing track keys when the SCORM track record already exists, see $trackdata in datamodel.php.
|
||||
// There, for performances reasons, columns are limited to: element, id, value, timemodified.
|
||||
// Missing fields are: userid, scormid, scoid, attempt.
|
||||
$track->userid = $userid;
|
||||
$track->scormid = $scormid;
|
||||
// Missing fields are: scoid, attempt.
|
||||
$track->scoid = $scoid;
|
||||
$track->attempt = $attempt;
|
||||
$track->attempt = $attempt->id;
|
||||
$track->id = $id;
|
||||
// Trigger submitted event.
|
||||
$event->add_record_snapshot('scorm_scoes_track', $track);
|
||||
$event->add_record_snapshot('scorm_scoes_value', $track);
|
||||
$event->add_record_snapshot('course_modules', $cm);
|
||||
$event->add_record_snapshot('scorm', $scorm);
|
||||
$event->trigger();
|
||||
@ -608,7 +613,7 @@ function scorm_insert_track($userid, $scormid, $scoid, $attempt, $element, $valu
|
||||
*/
|
||||
function scorm_has_tracks($scormid, $userid) {
|
||||
global $DB;
|
||||
return $DB->record_exists('scorm_scoes_track', array('userid' => $userid, 'scormid' => $scormid));
|
||||
return $DB->record_exists('scorm_attempt', ['userid' => $userid, 'scormid' => $scormid]);
|
||||
}
|
||||
|
||||
function scorm_get_tracks($scoid, $userid, $attempt='') {
|
||||
@ -616,14 +621,19 @@ function scorm_get_tracks($scoid, $userid, $attempt='') {
|
||||
global $DB;
|
||||
|
||||
if (empty($attempt)) {
|
||||
if ($scormid = $DB->get_field('scorm_scoes', 'scorm', array('id' => $scoid))) {
|
||||
if ($scormid = $DB->get_field('scorm_scoes', 'scorm', ['id' => $scoid])) {
|
||||
$attempt = scorm_get_last_attempt($scormid, $userid);
|
||||
} else {
|
||||
$attempt = 1;
|
||||
}
|
||||
}
|
||||
if ($tracks = $DB->get_records('scorm_scoes_track', array('userid' => $userid, 'scoid' => $scoid,
|
||||
'attempt' => $attempt), 'element ASC')) {
|
||||
$sql = "SELECT v.id, a.userid, a.scormid, v.scoid, a.attempt, v.value, v.timemodified, e.element
|
||||
FROM {scorm_attempt} a
|
||||
JOIN {scorm_scoes_value} v ON v.attemptid = a.id
|
||||
JOIN {scorm_element} e ON e.id = v.elementid
|
||||
WHERE a.userid = ? AND v.scoid = ? AND a.attempt = ?
|
||||
ORDER BY e.element ASC";
|
||||
if ($tracks = $DB->get_records_sql($sql, [$userid, $scoid, $attempt])) {
|
||||
$usertrack = scorm_format_interactions($tracks);
|
||||
$usertrack->userid = $userid;
|
||||
$usertrack->scoid = $scoid;
|
||||
@ -636,7 +646,7 @@ function scorm_get_tracks($scoid, $userid, $attempt='') {
|
||||
/**
|
||||
* helper function to return a formatted list of interactions for reports.
|
||||
*
|
||||
* @param array $trackdata the records from scorm_scoes_track table
|
||||
* @param array $trackdata the user tracking records from the database
|
||||
* @return object formatted list of interactions
|
||||
*/
|
||||
function scorm_format_interactions($trackdata) {
|
||||
@ -693,27 +703,24 @@ function scorm_format_interactions($trackdata) {
|
||||
function scorm_get_sco_runtime($scormid, $scoid, $userid, $attempt=1) {
|
||||
global $DB;
|
||||
|
||||
$timedata = new stdClass();
|
||||
$params = array('userid' => $userid, 'scormid' => $scormid, 'attempt' => $attempt);
|
||||
$sql = "SELECT min(timemodified) as start, max(timemodified) as finish
|
||||
FROM {scorm_scoes_value} v
|
||||
JOIN {scorm_attempt} a on a.id = v.attemptid
|
||||
WHERE a.userid = :userid AND a.scormid = :scormid AND a.attempt = :attempt";
|
||||
if (!empty($scoid)) {
|
||||
$params['scoid'] = $scoid;
|
||||
$sql .= " AND v.scoid = :scoid";
|
||||
}
|
||||
$tracks = $DB->get_records('scorm_scoes_track', $params, "timemodified ASC");
|
||||
if ($tracks) {
|
||||
$tracks = array_values($tracks);
|
||||
}
|
||||
|
||||
if ($tracks) {
|
||||
$timedata->start = $tracks[0]->timemodified;
|
||||
$timedata = $DB->get_record_sql($sql, $params);
|
||||
if (!empty($timedata)) {
|
||||
return $timedata;
|
||||
} else {
|
||||
$timedata = new stdClass();
|
||||
$timedata->start = false;
|
||||
|
||||
return $timedata;
|
||||
}
|
||||
if ($tracks && $track = array_pop($tracks)) {
|
||||
$timedata->finish = $track->timemodified;
|
||||
} else {
|
||||
$timedata->finish = $timedata->start;
|
||||
}
|
||||
return $timedata;
|
||||
}
|
||||
|
||||
function scorm_grade_user_attempt($scorm, $userid, $attempt=1) {
|
||||
@ -840,7 +847,7 @@ function scorm_get_last_attempt($scormid, $userid) {
|
||||
|
||||
// Find the last attempt number for the given user id and scorm id.
|
||||
$sql = "SELECT MAX(attempt)
|
||||
FROM {scorm_scoes_track}
|
||||
FROM {scorm_attempt}
|
||||
WHERE userid = ? AND scormid = ?";
|
||||
$lastattempt = $DB->get_field_sql($sql, array($userid, $scormid));
|
||||
if (empty($lastattempt)) {
|
||||
@ -863,7 +870,7 @@ function scorm_get_first_attempt($scormid, $userid) {
|
||||
|
||||
// Find the first attempt number for the given user id and scorm id.
|
||||
$sql = "SELECT MIN(attempt)
|
||||
FROM {scorm_scoes_track}
|
||||
FROM {scorm_attempt}
|
||||
WHERE userid = ? AND scormid = ?";
|
||||
|
||||
$lastattempt = $DB->get_field_sql($sql, array($userid, $scormid));
|
||||
@ -886,12 +893,14 @@ function scorm_get_last_completed_attempt($scormid, $userid) {
|
||||
global $DB;
|
||||
|
||||
// Find the last completed attempt number for the given user id and scorm id.
|
||||
$sql = "SELECT MAX(attempt)
|
||||
FROM {scorm_scoes_track}
|
||||
$sql = "SELECT MAX(a.attempt)
|
||||
FROM {scorm_attempt} a
|
||||
JOIN {scorm_scoes_value} v ON v.attemptid = a.id
|
||||
JOIN {scorm_element} e ON e.id = v.elementid
|
||||
WHERE userid = ? AND scormid = ?
|
||||
AND (".$DB->sql_compare_text('value')." = ".$DB->sql_compare_text('?')." OR ".
|
||||
$DB->sql_compare_text('value')." = ".$DB->sql_compare_text('?').")";
|
||||
$lastattempt = $DB->get_field_sql($sql, array($userid, $scormid, 'completed', 'passed'));
|
||||
AND (" . $DB->sql_compare_text('v.value') . " = " . $DB->sql_compare_text('?') . " OR ".
|
||||
$DB->sql_compare_text('v.value') . " = " . $DB->sql_compare_text('?') . ")";
|
||||
$lastattempt = $DB->get_field_sql($sql, [$userid, $scormid, 'completed', 'passed']);
|
||||
if (empty($lastattempt)) {
|
||||
return '1';
|
||||
} else {
|
||||
@ -910,8 +919,8 @@ function scorm_get_last_completed_attempt($scormid, $userid) {
|
||||
function scorm_get_all_attempts($scormid, $userid) {
|
||||
global $DB;
|
||||
$attemptids = array();
|
||||
$sql = "SELECT DISTINCT attempt FROM {scorm_scoes_track} WHERE userid = ? AND scormid = ? ORDER BY attempt";
|
||||
$attempts = $DB->get_records_sql($sql, array($userid, $scormid));
|
||||
$sql = "SELECT DISTINCT attempt FROM {scorm_attempt} WHERE userid = ? AND scormid = ? ORDER BY attempt";
|
||||
$attempts = $DB->get_records_sql($sql, [$userid, $scormid]);
|
||||
foreach ($attempts as $attempt) {
|
||||
$attemptids[] = $attempt->attempt;
|
||||
}
|
||||
@ -926,7 +935,7 @@ function scorm_get_all_attempts($scormid, $userid) {
|
||||
* @param string $action base URL for the organizations select box
|
||||
* @param stdClass $cm course module object
|
||||
*/
|
||||
function scorm_print_launch ($user, $scorm, $action, $cm) {
|
||||
function scorm_print_launch($user, $scorm, $action, $cm) {
|
||||
global $CFG, $DB, $OUTPUT;
|
||||
|
||||
if ($scorm->updatefreq == SCORM_UPDATE_EVERYTIME) {
|
||||
@ -1084,7 +1093,7 @@ function scorm_get_count_users($scormid, $groupingid=null) {
|
||||
|
||||
if (!empty($groupingid)) {
|
||||
$sql = "SELECT COUNT(DISTINCT st.userid)
|
||||
FROM {scorm_scoes_track} st
|
||||
FROM {scorm_attempt} st
|
||||
INNER JOIN {groups_members} gm ON st.userid = gm.userid
|
||||
INNER JOIN {groupings_groups} gg ON gm.groupid = gg.groupid
|
||||
WHERE st.scormid = ? AND gg.groupingid = ?
|
||||
@ -1092,7 +1101,7 @@ function scorm_get_count_users($scormid, $groupingid=null) {
|
||||
$params = array($scormid, $groupingid);
|
||||
} else {
|
||||
$sql = "SELECT COUNT(DISTINCT st.userid)
|
||||
FROM {scorm_scoes_track} st
|
||||
FROM {scorm_attempt} st
|
||||
WHERE st.scormid = ?
|
||||
";
|
||||
$params = array($scormid);
|
||||
@ -1334,7 +1343,7 @@ function scorm_get_attempt_status($user, $scorm, $cm='') {
|
||||
if (!empty($cm)) {
|
||||
$context = context_module::instance($cm->id);
|
||||
if (has_capability('mod/scorm:deleteownresponses', $context) &&
|
||||
$DB->record_exists('scorm_scoes_track', array('userid' => $user->id, 'scormid' => $scorm->id))) {
|
||||
$DB->record_exists('scorm_attempt', ['userid' => $user->id, 'scormid' => $scorm->id])) {
|
||||
// Check to see if any data is stored for this user.
|
||||
$deleteurl = new moodle_url($PAGE->url, array('action' => 'delete', 'sesskey' => sesskey()));
|
||||
$result .= $OUTPUT->single_button($deleteurl, get_string('deleteallattempts', 'scorm'));
|
||||
@ -1370,17 +1379,30 @@ function scorm_get_attempt_count($userid, $scorm, $returnobjects = false, $ignor
|
||||
$params = array('userid' => $userid, 'scormid' => $scorm->id);
|
||||
if ($ignoremissingcompletion) { // Exclude attempts that don't have the completion element requested.
|
||||
$params['element'] = $element;
|
||||
$sql = "SELECT DISTINCT a.attempt AS attemptnumber
|
||||
FROM {scorm_attempt} a
|
||||
JOIN {scorm_scoes_value} v ON v.attemptid = a.id
|
||||
JOIN {scorm_element} e ON e.id = v.elementid
|
||||
WHERE a.userid = :userid AND a.scormid = :scormid AND e.element = :element ORDER BY a.attempt";
|
||||
$attempts = $DB->get_records_sql($sql, $params);
|
||||
} else {
|
||||
$attempts = $DB->get_records('scorm_attempt', $params, 'attempt', 'DISTINCT attempt AS attemptnumber');
|
||||
}
|
||||
$attempts = $DB->get_records('scorm_scoes_track', $params, 'attempt', 'DISTINCT attempt AS attemptnumber');
|
||||
|
||||
return $attempts;
|
||||
} else {
|
||||
$params = array($userid, $scorm->id);
|
||||
$sql = "SELECT COUNT(DISTINCT attempt)
|
||||
FROM {scorm_scoes_track}
|
||||
WHERE userid = ? AND scormid = ?";
|
||||
$params = ['userid' => $userid, 'scormid' => $scorm->id];
|
||||
if ($ignoremissingcompletion) { // Exclude attempts that don't have the completion element requested.
|
||||
$sql .= ' AND element = ?';
|
||||
$params[] = $element;
|
||||
$params['element'] = $element;
|
||||
$sql = "SELECT COUNT(DISTINCT a.attempt)
|
||||
FROM {scorm_attempt} a
|
||||
JOIN {scorm_scoes_value} v ON v.attemptid = a.id
|
||||
JOIN {scorm_element} e ON e.id = v.elementid
|
||||
WHERE a.userid = :userid AND a.scormid = :scormid AND e.element = :element";
|
||||
} else {
|
||||
$sql = "SELECT COUNT(DISTINCT attempt)
|
||||
FROM {scorm_attempt}
|
||||
WHERE userid = :userid AND scormid = :scormid";
|
||||
}
|
||||
|
||||
$attemptscount = $DB->count_records_sql($sql, $params);
|
||||
@ -1453,22 +1475,26 @@ function scorm_delete_responses($attemptids, $scorm) {
|
||||
*
|
||||
* @param int $userid ID of User
|
||||
* @param stdClass $scorm Scorm object
|
||||
* @param int $attemptid user attempt that need to be deleted
|
||||
* @param int|stdClass $attemptornumber user attempt that need to be deleted
|
||||
*
|
||||
* @return bool true suceeded
|
||||
*/
|
||||
function scorm_delete_attempt($userid, $scorm, $attemptid) {
|
||||
global $DB;
|
||||
function scorm_delete_attempt($userid, $scorm, $attemptornumber) {
|
||||
if (is_object($attemptornumber)) {
|
||||
$attempt = $attemptornumber;
|
||||
} else {
|
||||
$attempt = scorm_get_attempt($userid, $scorm->id, $attemptornumber, false);
|
||||
}
|
||||
|
||||
$DB->delete_records('scorm_scoes_track', array('userid' => $userid, 'scormid' => $scorm->id, 'attempt' => $attemptid));
|
||||
scorm_delete_tracks($scorm->id, null, $userid, $attempt->id);
|
||||
$cm = get_coursemodule_from_instance('scorm', $scorm->id);
|
||||
|
||||
// Trigger instances list viewed event.
|
||||
$event = \mod_scorm\event\attempt_deleted::create(array(
|
||||
'other' => array('attemptid' => $attemptid),
|
||||
$event = \mod_scorm\event\attempt_deleted::create([
|
||||
'other' => ['attemptid' => $attempt->attempt],
|
||||
'context' => context_module::instance($cm->id),
|
||||
'relateduserid' => $userid
|
||||
));
|
||||
]);
|
||||
$event->add_record_snapshot('course_modules', $cm);
|
||||
$event->add_record_snapshot('scorm', $scorm);
|
||||
$event->trigger();
|
||||
@ -2496,6 +2522,123 @@ function scorm_update_calendar(stdClass $scorm, $cmid) {
|
||||
calendar_event::create($event, false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to delete user tracks from tables.
|
||||
*
|
||||
* @param int $scormid - id from scorm.
|
||||
* @param int $scoid - id of sco that needs to be deleted.
|
||||
* @param int $userid - userid that needs to be deleted.
|
||||
* @param int $attemptid - attemptid that should be deleted.
|
||||
* @since Moodle 4.3
|
||||
*/
|
||||
function scorm_delete_tracks($scormid, $scoid = null, $userid = null, $attemptid = null) {
|
||||
global $DB;
|
||||
|
||||
$usersql = '';
|
||||
$params = ['scormid' => $scormid];
|
||||
if (!empty($attemptid)) {
|
||||
$params['attemptid'] = $attemptid;
|
||||
$sql = "attemptid = :attemptid";
|
||||
} else {
|
||||
if (!empty($userid)) {
|
||||
$usersql = ' AND userid = :userid';
|
||||
$params['userid'] = $userid;
|
||||
}
|
||||
$sql = "attemptid in (SELECT id FROM {scorm_attempt} WHERE scormid = :scormid $usersql)";
|
||||
}
|
||||
|
||||
if (!empty($scoid)) {
|
||||
$params['scoid'] = $scoid;
|
||||
$sql .= " AND scoid = :scoid";
|
||||
}
|
||||
$DB->delete_records_select('scorm_scoes_value', $sql, $params);
|
||||
|
||||
if (empty($scoid)) {
|
||||
if (empty($attemptid)) {
|
||||
// Scoid is empty so we delete the attempt as well.
|
||||
$DB->delete_records('scorm_attempt', $params);
|
||||
} else {
|
||||
$DB->delete_records('scorm_attempt', ['id' => $attemptid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get specific scorm track data.
|
||||
* Note: the $attempt var is optional as SCORM 2004 code doesn't always use it, probably a bug,
|
||||
* but we do not want to change SCORM 2004 behaviour right now.
|
||||
*
|
||||
* @param int $scoid - scoid.
|
||||
* @param int $userid - user id of user.
|
||||
* @param string $element - name of element being requested.
|
||||
* @param int $attempt - attempt number (not id)
|
||||
* @since Moodle 4.3
|
||||
* @return mixed
|
||||
*/
|
||||
function scorm_get_sco_value($scoid, $userid, $element, $attempt = null): ?stdClass {
|
||||
global $DB;
|
||||
$params = ['scoid' => $scoid, 'userid' => $userid, 'element' => $element];
|
||||
|
||||
$sql = "SELECT a.id, a.userid, a.scormid, a.attempt, v.id as valueid, v.scoid, v.value, v.timemodified, e.element
|
||||
FROM {scorm_attempt} a
|
||||
JOIN {scorm_scoes_value} v ON v.attemptid = a.id
|
||||
JOIN {scorm_element} e on e.id = v.elementid
|
||||
WHERE v.scoid = :scoid AND a.userid = :userid AND e.element = :element";
|
||||
|
||||
if ($attempt !== null) {
|
||||
$params['attempt'] = $attempt;
|
||||
$sql .= " AND a.attempt = :attempt";
|
||||
}
|
||||
$value = $DB->get_record_sql($sql, $params);
|
||||
return $value ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attempt record, allow one to be created if doesn't exist.
|
||||
*
|
||||
* @param int $userid - user id.
|
||||
* @param int $scormid - SCORM id.
|
||||
* @param int $attempt - attempt number.
|
||||
* @param boolean $create - should an attempt record be created if it does not exist.
|
||||
* @since Moodle 4.3
|
||||
* @return stdclass
|
||||
*/
|
||||
function scorm_get_attempt($userid, $scormid, $attempt, $create = true): ?stdClass {
|
||||
global $DB;
|
||||
$params = ['scormid' => $scormid, 'userid' => $userid, 'attempt' => $attempt];
|
||||
$attemptobject = $DB->get_record('scorm_attempt', $params);
|
||||
if (empty($attemptobject) && $create) {
|
||||
// Create new attempt.
|
||||
$attemptobject = new stdClass();
|
||||
$attemptobject->userid = $userid;
|
||||
$attemptobject->attempt = $attempt;
|
||||
$attemptobject->scormid = $scormid;
|
||||
$attemptobject->id = $DB->insert_record('scorm_attempt', $attemptobject);
|
||||
}
|
||||
return $attemptobject ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Scorm element id from cache, allow one to be created if doesn't exist.
|
||||
*
|
||||
* @param string $elementname - name of element that is being requested.
|
||||
* @since Moodle 4.3
|
||||
* @return int - element id.
|
||||
*/
|
||||
function scorm_get_elementid($elementname): ?int {
|
||||
global $DB;
|
||||
$cache = cache::make('mod_scorm', 'elements');
|
||||
$element = $cache->get($elementname);
|
||||
if (empty($element)) {
|
||||
// Create new attempt.
|
||||
$element = new stdClass();
|
||||
$element->element = $elementname;
|
||||
$elementid = $DB->insert_record('scorm_element', $element);
|
||||
$cache->set($elementname, $elementid);
|
||||
return $elementid;
|
||||
} else {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
@ -274,32 +274,32 @@ class report extends \mod_scorm\report {
|
||||
$csvexport->add_data($headers);
|
||||
}
|
||||
// Construct the SQL.
|
||||
$select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, ';
|
||||
$select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(sa.attempt, 0)').' AS uniqueid, ';
|
||||
// TODO Does not support custom user profile fields (MDL-70456).
|
||||
$userfields = \core_user\fields::for_identity($coursecontext, false)->with_userpic()->including('idnumber');
|
||||
$selectfields = $userfields->get_sql('u', false, '', 'userid')->selects;
|
||||
$select .= 'st.scormid AS scormid, st.attempt AS attempt ' . $selectfields . ' ';
|
||||
$select .= 'sa.scormid AS scormid, sa.attempt AS attempt ' . $selectfields . ' ';
|
||||
|
||||
// This part is the same for all cases - join users and scorm_scoes_track tables.
|
||||
// This part is the same for all cases - join users and user tracking tables.
|
||||
$from = 'FROM {user} u ';
|
||||
$from .= 'LEFT JOIN {scorm_scoes_track} st ON st.userid = u.id AND st.scormid = '.$scorm->id;
|
||||
$from .= 'LEFT JOIN {scorm_attempt} sa ON sa.userid = u.id AND sa.scormid = '.$scorm->id;
|
||||
switch ($attemptsmode) {
|
||||
case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH:
|
||||
// Show only students with attempts.
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NOT NULL";
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND sa.userid IS NOT NULL";
|
||||
break;
|
||||
case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO:
|
||||
// Show only students without attempts.
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NULL";
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND sa.userid IS NULL";
|
||||
break;
|
||||
case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS:
|
||||
// Show all students with or without attempts.
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND (st.userid IS NOT NULL OR st.userid IS NULL)";
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND (sa.userid IS NOT NULL OR sa.userid IS NULL)";
|
||||
break;
|
||||
}
|
||||
|
||||
$countsql = 'SELECT COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').')) AS nbresults, ';
|
||||
$countsql .= 'COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'st.attempt').')) AS nbattempts, ';
|
||||
$countsql = 'SELECT COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(sa.attempt, 0)').')) AS nbresults, ';
|
||||
$countsql .= 'COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'sa.attempt').')) AS nbattempts, ';
|
||||
$countsql .= 'COUNT(DISTINCT(u.id)) AS nbusers ';
|
||||
$countsql .= $from.$where;
|
||||
|
||||
|
@ -61,13 +61,14 @@ class report extends \mod_scorm\report {
|
||||
$params = array_merge($params, ['scoid' => $scoid]);
|
||||
|
||||
// Construct the SQL.
|
||||
$sql = "SELECT DISTINCT " . $DB->sql_concat('st.userid', '\'#\'', 'COALESCE(st.attempt, 0)') . " AS uniqueid,
|
||||
st.userid AS userid,
|
||||
st.scormid AS scormid,
|
||||
st.attempt AS attempt,
|
||||
st.scoid AS scoid
|
||||
FROM {scorm_scoes_track} st
|
||||
WHERE st.userid IN ({$allowedlist}) AND st.scoid = :scoid";
|
||||
$sql = "SELECT DISTINCT " . $DB->sql_concat('a.userid', '\'#\'', 'COALESCE(a.attempt, 0)') . " AS uniqueid,
|
||||
a.userid AS userid,
|
||||
a.scormid AS scormid,
|
||||
a.attempt AS attempt,
|
||||
v.scoid AS scoid
|
||||
FROM {scorm_attempt} a
|
||||
JOIN {scorm_scoes_value} v ON v.attemptid = a.id
|
||||
WHERE a.userid IN ({$allowedlist}) AND v.scoid = :scoid";
|
||||
$attempts = $DB->get_records_sql($sql, $params);
|
||||
|
||||
$usergrades = [];
|
||||
|
@ -163,32 +163,32 @@ class report extends \mod_scorm\report {
|
||||
}
|
||||
|
||||
// Construct the SQL.
|
||||
$select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, ';
|
||||
$select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(sa.attempt, 0)').' AS uniqueid, ';
|
||||
// TODO Does not support custom user profile fields (MDL-70456).
|
||||
$userfields = \core_user\fields::for_identity($coursecontext, false)->with_userpic()->including('idnumber');
|
||||
$selectfields = $userfields->get_sql('u', false, '', 'userid')->selects;
|
||||
$select .= 'st.scormid AS scormid, st.attempt AS attempt ' . $selectfields . ' ';
|
||||
$select .= 'sa.scormid AS scormid, sa.attempt AS attempt ' . $selectfields . ' ';
|
||||
|
||||
// This part is the same for all cases - join users and scorm_scoes_track tables.
|
||||
// This part is the same for all cases - join users and user tracking tables.
|
||||
$from = 'FROM {user} u ';
|
||||
$from .= 'LEFT JOIN {scorm_scoes_track} st ON st.userid = u.id AND st.scormid = '.$scorm->id;
|
||||
$from .= 'LEFT JOIN {scorm_attempt} sa ON sa.userid = u.id AND sa.scormid = '.$scorm->id;
|
||||
switch ($attemptsmode) {
|
||||
case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH:
|
||||
// Show only students with attempts.
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NOT NULL";
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND sa.userid IS NOT NULL";
|
||||
break;
|
||||
case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO:
|
||||
// Show only students without attempts.
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NULL";
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND sa.userid IS NULL";
|
||||
break;
|
||||
case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS:
|
||||
// Show all students with or without attempts.
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND (st.userid IS NOT NULL OR st.userid IS NULL)";
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND (sa.userid IS NOT NULL OR sa.userid IS NULL)";
|
||||
break;
|
||||
}
|
||||
|
||||
$countsql = 'SELECT COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').')) AS nbresults, ';
|
||||
$countsql .= 'COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'st.attempt').')) AS nbattempts, ';
|
||||
$countsql = 'SELECT COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(sa.attempt, 0)').')) AS nbresults, ';
|
||||
$countsql .= 'COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'sa.attempt').')) AS nbattempts, ';
|
||||
$countsql .= 'COUNT(DISTINCT(u.id)) AS nbusers ';
|
||||
$countsql .= $from.$where;
|
||||
$questioncount = get_scorm_question_count($scorm->id);
|
||||
|
@ -157,32 +157,32 @@ class report extends \mod_scorm\report {
|
||||
}
|
||||
|
||||
// Construct the SQL.
|
||||
$select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, ';
|
||||
$select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(sa.attempt, 0)').' AS uniqueid, ';
|
||||
// TODO Does not support custom user profile fields (MDL-70456).
|
||||
$userfields = \core_user\fields::for_identity($coursecontext, false)->with_userpic()->including('idnumber');
|
||||
$selectfields = $userfields->get_sql('u', false, '', 'userid')->selects;
|
||||
$select .= 'st.scormid AS scormid, st.attempt AS attempt ' . $selectfields . ' ';
|
||||
$select .= 'sa.scormid AS scormid, sa.attempt AS attempt ' . $selectfields . ' ';
|
||||
|
||||
// This part is the same for all cases - join users and scorm_scoes_track tables.
|
||||
// This part is the same for all cases - join users and user tracking tables.
|
||||
$from = 'FROM {user} u ';
|
||||
$from .= 'LEFT JOIN {scorm_scoes_track} st ON st.userid = u.id AND st.scormid = '.$scorm->id;
|
||||
$from .= 'LEFT JOIN {scorm_attempt} sa ON sa.userid = u.id AND sa.scormid = '.$scorm->id;
|
||||
switch ($attemptsmode) {
|
||||
case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH:
|
||||
// Show only students with attempts.
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NOT NULL";
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND sa.userid IS NOT NULL";
|
||||
break;
|
||||
case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO:
|
||||
// Show only students without attempts.
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND st.userid IS NULL";
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND sa.userid IS NULL";
|
||||
break;
|
||||
case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS:
|
||||
// Show all students with or without attempts.
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND (st.userid IS NOT NULL OR st.userid IS NULL)";
|
||||
$where = " WHERE u.id IN ({$allowedlistsql}) AND (sa.userid IS NOT NULL OR sa.userid IS NULL)";
|
||||
break;
|
||||
}
|
||||
|
||||
$countsql = 'SELECT COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').')) AS nbresults, ';
|
||||
$countsql .= 'COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'st.attempt').')) AS nbattempts, ';
|
||||
$countsql = 'SELECT COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(sa.attempt, 0)').')) AS nbresults, ';
|
||||
$countsql .= 'COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'sa.attempt').')) AS nbattempts, ';
|
||||
$countsql .= 'COUNT(DISTINCT(u.id)) AS nbusers ';
|
||||
$countsql .= $from.$where;
|
||||
|
||||
@ -620,23 +620,22 @@ class report extends \mod_scorm\report {
|
||||
*/
|
||||
function get_scorm_objectives($scormid) {
|
||||
global $DB;
|
||||
$objectives = array();
|
||||
$params = array();
|
||||
$select = "scormid = ? AND ";
|
||||
$select .= $DB->sql_like("element", "?", false);
|
||||
$params[] = $scormid;
|
||||
$params[] = "cmi.objectives%.id";
|
||||
$value = $DB->sql_compare_text('value');
|
||||
$rs = $DB->get_recordset_select("scorm_scoes_track", $select, $params, 'value', "DISTINCT $value AS value, scoid");
|
||||
if ($rs->valid()) {
|
||||
foreach ($rs as $record) {
|
||||
$objectives[$record->scoid][] = $record->value;
|
||||
}
|
||||
// Now naturally sort the sco arrays.
|
||||
foreach ($objectives as $scoid => $sco) {
|
||||
natsort($objectives[$scoid]);
|
||||
}
|
||||
$objectives = [];
|
||||
$params = ['scormid' => $scormid, 'search' => 'cmi.objectives%.id'];
|
||||
|
||||
$value = $DB->sql_compare_text('v.value');
|
||||
$sql = "SELECT DISTINCT $value as value, ss.id
|
||||
FROM {scorm_scoes_value} v
|
||||
JOIN {scorm_scoes} ss ON ss.id = v.scoid AND ss.scorm = :scormid
|
||||
JOIN {scorm_element} e ON v.elementid = e.id
|
||||
WHERE ".$DB->sql_like("element", ":search", false);
|
||||
$rs = $DB->get_records_sql($sql, $params);
|
||||
foreach ($rs as $record) {
|
||||
$objectives[$record->scoid][] = $record->value;
|
||||
}
|
||||
// Now naturally sort the sco arrays.
|
||||
foreach ($objectives as $scoid => $sco) {
|
||||
natsort($objectives[$scoid]);
|
||||
}
|
||||
$rs->close();
|
||||
return $objectives;
|
||||
}
|
||||
|
@ -75,11 +75,16 @@ function get_scorm_question_count($scormid) {
|
||||
global $DB;
|
||||
$count = 0;
|
||||
$params = array();
|
||||
$select = "scormid = ? AND ";
|
||||
$select .= $DB->sql_like("element", "?", false);
|
||||
$sql = "SELECT DISTINCT e.id, e.element
|
||||
FROM {scorm_element} e
|
||||
JOIN {scorm_scoes_value} v ON e.id = v.elementid
|
||||
JOIN {scorm_attempt} a ON a.id = v.attemptid
|
||||
WHERE a.scormid = ? AND ". $DB->sql_like("element", "?", false) .
|
||||
" ORDER BY e.element";
|
||||
|
||||
$params[] = $scormid;
|
||||
$params[] = "cmi.interactions_%.id";
|
||||
$rs = $DB->get_recordset_select("scorm_scoes_track", $select, $params, 'element');
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
$keywords = array("cmi.interactions_", ".id");
|
||||
if ($rs->valid()) {
|
||||
foreach ($rs as $record) {
|
||||
|
@ -69,8 +69,12 @@ $event->add_record_snapshot('course_modules', $cm);
|
||||
$event->add_record_snapshot('scorm', $scorm);
|
||||
$event->trigger();
|
||||
|
||||
$trackdata = $DB->get_records('scorm_scoes_track', array('userid' => $user->id, 'scormid' => $scorm->id,
|
||||
'attempt' => $attempt));
|
||||
$sql = "SELECT a.id, a.userid, a.scormid, v.scoid, a.attempt, v.value, v.timemodified, e.element
|
||||
FROM {scorm_attempt} a
|
||||
JOIN {scorm_scoes_value} v ON v.attemptid = a.id
|
||||
JOIN {scorm_element} e ON e.id = v.elementid
|
||||
WHERE a.userid = :userid AND a.scormid = :scormid AND a.attempt = :attempt";
|
||||
$trackdata = $DB->get_records_sql($sql, ['userid' => $userid, 'scormid' => $scorm->id, 'attempt' => $attempt]);
|
||||
$usertrack = scorm_format_interactions($trackdata);
|
||||
|
||||
$questioncount = get_scorm_question_count($scorm->id);
|
||||
|
@ -41,7 +41,7 @@ class restore_date_test extends \restore_date_testcase {
|
||||
scorm_insert_track($USER->id, $scorm->id, $sco->id, 4, 'cmi.core.score.raw', 10);
|
||||
|
||||
// We do not want second differences to fail our test because of execution delays.
|
||||
$DB->set_field('scorm_scoes_track', 'timemodified', $time);
|
||||
$DB->set_field('scorm_scoes_value', 'timemodified', $time);
|
||||
|
||||
// Do backup and restore.
|
||||
$newcourseid = $this->backup_and_restore($course);
|
||||
@ -51,7 +51,11 @@ class restore_date_test extends \restore_date_testcase {
|
||||
$props = ['timeopen', 'timeclose'];
|
||||
$this->assertFieldsRolledForward($scorm, $newscorm, $props);
|
||||
|
||||
$tracks = $DB->get_records('scorm_scoes_track', ['scormid' => $newscorm->id]);
|
||||
$sql = "SELECT *
|
||||
FROM {scorm_scoes_value} v
|
||||
JOIN {scorm_attempt} a ON a.id = v.attemptid
|
||||
WHERE a.scormid = ?";
|
||||
$tracks = $DB->get_records_sql($sql, [$newscorm->id]);
|
||||
foreach ($tracks as $track) {
|
||||
$this->assertEquals($time, $track->timemodified);
|
||||
}
|
||||
|
@ -504,9 +504,12 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$result = mod_scorm_external::insert_scorm_tracks($sco->id, 1, $tracks);
|
||||
$result = external_api::clean_returnvalue(mod_scorm_external::insert_scorm_tracks_returns(), $result);
|
||||
$this->assertCount(0, $result['warnings']);
|
||||
|
||||
$trackids = $DB->get_records('scorm_scoes_track', array('userid' => $student->id, 'scoid' => $sco->id,
|
||||
'scormid' => $scorm->id, 'attempt' => 1));
|
||||
$sql = "SELECT v.id
|
||||
FROM {scorm_scoes_value} v
|
||||
JOIN {scorm_attempt} a ON a.id = v.attemptid
|
||||
WHERE a.userid = :userid AND a.attempt = :attempt AND a.scormid = :scormid AND v.scoid = :scoid";
|
||||
$params = ['userid' => $student->id, 'scoid' => $sco->id, 'scormid' => $scorm->id, 'attempt' => 1];
|
||||
$trackids = $DB->get_records_sql($sql, $params);
|
||||
// We use asort here to prevent problems with ids ordering.
|
||||
$expectedkeys = array_keys($trackids);
|
||||
$this->assertEquals(asort($expectedkeys), asort($result['trackids']));
|
||||
|
@ -158,8 +158,8 @@ class provider_test extends provider_testcase {
|
||||
$this->setAdminUser();
|
||||
$this->scorm_setup_test_scenario_data();
|
||||
|
||||
// Before deletion, we should have 8 entries in the scorm_scoes_track table.
|
||||
$count = $DB->count_records('scorm_scoes_track');
|
||||
// Before deletion, we should have 8 entries in the scorm_scoes_value table.
|
||||
$count = $DB->count_records('scorm_scoes_value');
|
||||
$this->assertEquals(8, $count);
|
||||
// Before deletion, we should have 4 entries in the scorm_aicc_session table.
|
||||
$count = $DB->count_records('scorm_aicc_session');
|
||||
@ -168,8 +168,8 @@ class provider_test extends provider_testcase {
|
||||
// Delete data based on the context.
|
||||
provider::delete_data_for_all_users_in_context($this->context);
|
||||
|
||||
// After deletion, the scorm_scoes_track entries should have been deleted.
|
||||
$count = $DB->count_records('scorm_scoes_track');
|
||||
// After deletion, the scorm_scoes_value entries should have been deleted.
|
||||
$count = $DB->count_records('scorm_scoes_value');
|
||||
$this->assertEquals(0, $count);
|
||||
// After deletion, the scorm_aicc_session entries should have been deleted.
|
||||
$count = $DB->count_records('scorm_aicc_session');
|
||||
@ -186,8 +186,8 @@ class provider_test extends provider_testcase {
|
||||
$this->setAdminUser();
|
||||
$this->scorm_setup_test_scenario_data();
|
||||
|
||||
// Before deletion, we should have 8 entries in the scorm_scoes_track table.
|
||||
$count = $DB->count_records('scorm_scoes_track');
|
||||
// Before deletion, we should have 8 entries in the scorm_scoes_value table.
|
||||
$count = $DB->count_records('scorm_scoes_value');
|
||||
$this->assertEquals(8, $count);
|
||||
// Before deletion, we should have 4 entries in the scorm_aicc_session table.
|
||||
$count = $DB->count_records('scorm_aicc_session');
|
||||
@ -196,10 +196,10 @@ class provider_test extends provider_testcase {
|
||||
$approvedcontextlist = new approved_contextlist($this->student1, 'scorm', [$this->context->id]);
|
||||
provider::delete_data_for_user($approvedcontextlist);
|
||||
|
||||
// After deletion, the scorm_scoes_track entries for the first student should have been deleted.
|
||||
$count = $DB->count_records('scorm_scoes_track', ['userid' => $this->student1->id]);
|
||||
// After deletion, the scorm_attempt entries for the first student should have been deleted.
|
||||
$count = $DB->count_records('scorm_attempt', ['userid' => $this->student1->id]);
|
||||
$this->assertEquals(0, $count);
|
||||
$count = $DB->count_records('scorm_scoes_track');
|
||||
$count = $DB->count_records('scorm_scoes_value');
|
||||
$this->assertEquals(4, $count);
|
||||
// After deletion, the scorm_aicc_session entries for the first student should have been deleted.
|
||||
$count = $DB->count_records('scorm_aicc_session', ['userid' => $this->student1->id]);
|
||||
@ -214,7 +214,7 @@ class provider_test extends provider_testcase {
|
||||
// Delete scoes_track for student0 (nothing has to be removed).
|
||||
$approvedcontextlist = new approved_contextlist($this->student0, 'scorm', [$this->context->id]);
|
||||
provider::delete_data_for_user($approvedcontextlist);
|
||||
$count = $DB->count_records('scorm_scoes_track');
|
||||
$count = $DB->count_records('scorm_scoes_value');
|
||||
$this->assertEquals(4, $count);
|
||||
$count = $DB->count_records('scorm_aicc_session');
|
||||
$this->assertEquals(2, $count);
|
||||
@ -231,8 +231,8 @@ class provider_test extends provider_testcase {
|
||||
$this->setAdminUser();
|
||||
$this->scorm_setup_test_scenario_data();
|
||||
|
||||
// Before deletion, we should have 8 entries in the scorm_scoes_track table.
|
||||
$count = $DB->count_records('scorm_scoes_track');
|
||||
// Before deletion, we should have 8 entries in the scorm_scoes_value table.
|
||||
$count = $DB->count_records('scorm_scoes_value');
|
||||
$this->assertEquals(8, $count);
|
||||
// Before deletion, we should have 4 entries in the scorm_aicc_session table.
|
||||
$count = $DB->count_records('scorm_aicc_session');
|
||||
@ -243,10 +243,10 @@ class provider_test extends provider_testcase {
|
||||
$approvedlist = new approved_userlist($this->context, $component, $approveduserids);
|
||||
provider::delete_data_for_users($approvedlist);
|
||||
|
||||
// After deletion, the scorm_scoes_track entries for the first student should have been deleted.
|
||||
$count = $DB->count_records('scorm_scoes_track', ['userid' => $this->student1->id]);
|
||||
// After deletion, the scorm_attempt entries for the first student should have been deleted.
|
||||
$count = $DB->count_records('scorm_attempt', ['userid' => $this->student1->id]);
|
||||
$this->assertEquals(0, $count);
|
||||
$count = $DB->count_records('scorm_scoes_track');
|
||||
$count = $DB->count_records('scorm_scoes_value');
|
||||
$this->assertEquals(4, $count);
|
||||
|
||||
// After deletion, the scorm_aicc_session entries for the first student should have been deleted.
|
||||
@ -264,7 +264,7 @@ class provider_test extends provider_testcase {
|
||||
$approvedlist = new approved_userlist($this->context, $component, $approveduserids);
|
||||
provider::delete_data_for_users($approvedlist);
|
||||
|
||||
$count = $DB->count_records('scorm_scoes_track');
|
||||
$count = $DB->count_records('scorm_scoes_value');
|
||||
$this->assertEquals(4, $count);
|
||||
$count = $DB->count_records('scorm_aicc_session');
|
||||
$this->assertEquals(2, $count);
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2023042400; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2023042403; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023041800; // Requires this Moodle version.
|
||||
$plugin->component = 'mod_scorm'; // Full name of the plugin (used for diagnostics).
|
||||
$plugin->component = 'mod_scorm'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
|
@ -152,7 +152,7 @@ if (!empty($action) && confirm_sesskey() && has_capability('mod/scorm:deleteownr
|
||||
exit;
|
||||
} else if ($action == 'deleteconfirm') {
|
||||
// Delete this users attempts.
|
||||
$DB->delete_records('scorm_scoes_track', array('userid' => $USER->id, 'scormid' => $scorm->id));
|
||||
scorm_delete_tracks($scorm->id, null, $USER->id);
|
||||
scorm_update_grades($scorm, $USER->id, true);
|
||||
echo $OUTPUT->notification(get_string('scormresponsedeleted', 'scorm'), 'notifysuccess');
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user