glossary portfolio caller - fixing tiny bug - incorrectly named string key (thanks...
[moodle.git] / mod / scorm / locallib.php
CommitLineData
e4aa175a 1<?php // $Id$
f69db63e 2
9528568b 3require_once("$CFG->dirroot/mod/scorm/lib.php");
4
a30b6819 5/// Constants and settings for module scorm
a679d64d 6define('UPDATE_NEVER', '0');
7define('UPDATE_ONCHANGE', '1');
8define('UPDATE_EVERYDAY', '2');
9define('UPDATE_EVERYTIME', '3');
10
b3659259 11define('SCO_ALL', 0);
12define('SCO_DATA', 1);
13define('SCO_ONLY', 2);
a30b6819 14
15define('GRADESCOES', '0');
16define('GRADEHIGHEST', '1');
17define('GRADEAVERAGE', '2');
18define('GRADESUM', '3');
a30b6819 19
20define('HIGHESTATTEMPT', '0');
21define('AVERAGEATTEMPT', '1');
22define('FIRSTATTEMPT', '2');
23define('LASTATTEMPT', '3');
a30b6819 24
a30b6819 25
9528568b 26/// Local Library of functions for module scorm
a30b6819 27
9528568b 28/**
29 * Extracts scrom package, sets up all variables.
30 * Called whenever scorm changes
31 * @param object $scorm instance - fields are updated and changes saved into database
32 * @param bool $full force full update if true
33 * @return void
34 */
35function scorm_parse($scorm, $full) {
36 global $CFG, $DB;
8aee93f1 37
9528568b 38 if (!isset($scorm->cmid)) {
39 $cm = get_coursemodule_from_instance('scorm', $scorm->id);
40 $scorm->cmid = $cm->id;
41 }
42 $context = get_context_instance(CONTEXT_MODULE, $scorm->cmid);
43 $newhash = $scorm->sha1hash;
a30b6819 44
9528568b 45 if ($scorm->scormtype === SCORM_TYPE_LOCAL or $scorm->scormtype === SCORM_TYPE_LOCALSYNC) {
a30b6819 46
9528568b 47 $fs = get_file_storage();
48 $packagefile = false;
f69db63e 49
9528568b 50 if ($scorm->scormtype === SCORM_TYPE_LOCAL) {
51 if ($packagefile = $fs->get_file($context->id, 'scorm_package', 0, '/', $scorm->reference)) {
52 $newhash = $packagefile->get_contenthash();
53 } else {
54 $newhash = null;
55 }
56 } else {
57 if (!$CFG->scorm_allowtypelocalsync) {
58 // sorry - localsync disabled
59 return;
60 }
61 if ($scorm->reference !== '' and (!$full or $scorm->sha1hash !== sha1($scorm->reference))) {
62 $fs->delete_area_files($context->id, 'scorm_package');
63 $file_record = array('contextid'=>$context->id, 'filearea'=>'scorm_package', 'itemid'=>0, 'filepath'=>'/');
64 if ($packagefile = $fs->create_file_from_url($file_record, $scorm->reference)) {
65 $newhash = sha1($scorm->reference);
5c1ac70c 66 } else {
9528568b 67 $newhash = null;
5c1ac70c 68 }
f69db63e 69 }
70 }
f69db63e 71
9528568b 72 if ($packagefile) {
73 if (!$full and $packagefile and $scorm->sha1hash === $newhash) {
74 if (strpos($scorm->version, 'SCORM') !== false) {
75 if ($fs->get_file($context->id, 'scorm_content', 0, '/', 'imsmanifest.xml')) {
76 // no need to update
77 return;
e4aa175a 78 }
9528568b 79 } else if (strpos($scorm->version, 'AICC') !== false) {
80 // TODO: add more sanity checks - something really exists in scorm_content area
81 return;
82 }
83 }
84
85 // now extract files
86 $fs->delete_area_files($context->id, 'scorm_content');
87
88 $packer = get_file_packer('application/zip');
89 $packagefile->extract_to_storage($packer, $context->id, 'scorm_content', 0, '/');
90
91 } else if (!$full) {
92 return;
93 }
94
95
96 if ($manifest = $fs->get_file($context->id, 'scorm_content', 0, '/', 'imsmanifest.xml')) {
97 require_once("$CFG->dirroot/mod/scorm/datamodels/scormlib.php");
98 // SCORM
99 if (!scorm_parse_scorm($scorm, $manifest)) {
100 $scorm->version = 'ERROR';
101 }
102 } else {
103 require_once("$CFG->dirroot/mod/scorm/datamodels/aicclib.php");
104 // AICC
105 if (!scorm_parse_aicc($scorm)) {
106 $scorm->version = 'ERROR';
107 }
108 }
109
110 } else if ($scorm->scormtype === SCORM_TYPE_EXTERNAL and $CFG->scorm_allowtypeexternal) {
111 if (!$full and $scorm->sha1hash === sha1($scorm->reference)) {
112 return;
113 }
114 require_once("$CFG->dirroot/mod/scorm/datamodels/scormlib.php");
115 // SCORM only, AICC can not be external
116 if (!scorm_parse_scorm($scorm, $scorm->reference)) {
117 $scorm->version = 'ERROR';
118 }
119 $newhash = sha1($scorm->reference);
120
121 } else if ($scorm->scormtype === SCORM_TYPE_IMSREPOSITORY and !empty($CFG->repositoryactivate) and $CFG->scorm_allowtypeimsrepository) {
122 if (!$full and $scorm->sha1hash === sha1($scorm->reference)) {
123 return;
124 }
125 require_once("$CFG->dirroot/mod/scorm/datamodels/scormlib.php");
126 if (!scorm_parse_scorm($scorm, $CFG->repository.substr($scorm->reference,1).'/imsmanifest.xml')) {
127 $scorm->version = 'ERROR';
128 }
129 $newhash = sha1($scorm->reference);
130
e4aa175a 131 } else {
9528568b 132 // sorry, disabled type
133 return;
e4aa175a 134 }
9528568b 135
136 $scorm->revision++;
137 $scorm->sha1hash = $newhash;
138 $DB->update_record('scorm', $scorm);
e4aa175a 139}
140
9528568b 141
2b3447c3 142function scorm_array_search($item, $needle, $haystacks, $strict=false) {
143 if (!empty($haystacks)) {
144 foreach ($haystacks as $key => $element) {
145 if ($strict) {
146 if ($element->{$item} === $needle) {
147 return $key;
148 }
149 } else {
150 if ($element->{$item} == $needle) {
151 return $key;
e4aa175a 152 }
153 }
e4aa175a 154 }
155 }
2b3447c3 156 return false;
e4aa175a 157}
158
2b3447c3 159function scorm_repeater($what, $times) {
160 if ($times <= 0) {
161 return null;
162 }
163 $return = '';
164 for ($i=0; $i<$times;$i++) {
165 $return .= $what;
166 }
167 return $return;
168}
e4aa175a 169
2b3447c3 170function scorm_external_link($link) {
171// check if a link is external
172 $result = false;
173 $link = strtolower($link);
174 if (substr($link,0,7) == 'http://') {
175 $result = true;
176 } else if (substr($link,0,8) == 'https://') {
177 $result = true;
178 } else if (substr($link,0,4) == 'www.') {
179 $result = true;
180 }
181 return $result;
e4aa175a 182}
183
b3659259 184/**
185* Returns an object containing all datas relative to the given sco ID
186*
187* @param integer $id The sco ID
188* @return mixed (false if sco id does not exists)
189*/
bd3523a5 190
b3659259 191function scorm_get_sco($id,$what=SCO_ALL) {
bf347041 192 global $DB;
193
194 if ($sco = $DB->get_record('scorm_scoes', array('id'=>$id))) {
b3659259 195 $sco = ($what == SCO_DATA) ? new stdClass() : $sco;
bf347041 196 if (($what != SCO_ONLY) && ($scodatas = $DB->get_records('scorm_scoes_data', array('scoid'=>$id)))) {
b3659259 197 foreach ($scodatas as $scodata) {
c31f631b 198 $sco->{$scodata->name} = $scodata->value;
b3659259 199 }
bf347041 200 } else if (($what != SCO_ONLY) && (!($scodatas = $DB->get_records('scorm_scoes_data', array('scoid'=>$id))))) {
9528568b 201 $sco->parameters = '';
b3659259 202 }
203 return $sco;
204 } else {
205 return false;
206 }
207}
82605bea 208
209/**
210* Returns an object (array) containing all the scoes data related to the given sco ID
211*
212* @param integer $id The sco ID
213* @param integer $organisation an organisation ID - defaults to false if not required
214* @return mixed (false if there are no scoes or an array)
215*/
216
217function scorm_get_scoes($id,$organisation=false) {
b44c704f 218 global $DB;
219
82605bea 220 $organizationsql = '';
b44c704f 221 $queryarray = array('scorm'=>$id);
82605bea 222 if (!empty($organisation)) {
b44c704f 223 $queryarray['organization'] = $organisation;
82605bea 224 }
b44c704f 225 if ($scoes = $DB->get_records('scorm_scoes', $queryarray, 'id ASC')) {
82605bea 226 // drop keys so that it is a simple array as expected
227 $scoes = array_values($scoes);
228 foreach ($scoes as $sco) {
b44c704f 229 if ($scodatas = $DB->get_records('scorm_scoes_data',array('scoid'=>$sco->id))) {
82605bea 230 foreach ($scodatas as $scodata) {
231 $sco->{$scodata->name} = stripslashes_safe($scodata->value);
232 }
233 }
234 }
235 return $scoes;
236 } else {
237 return false;
238 }
239}
240
e4aa175a 241function scorm_insert_track($userid,$scormid,$scoid,$attempt,$element,$value) {
bf347041 242 global $DB;
243
e4aa175a 244 $id = null;
bf347041 245 if ($track = $DB->get_record('scorm_scoes_track',array('userid'=>$userid, 'scormid'=>$scormid, 'scoid'=>$scoid, 'attempt'=>$attempt, 'element'=>$element))) {
e4aa175a 246 $track->value = $value;
247 $track->timemodified = time();
bf347041 248 $id = $DB->update_record('scorm_scoes_track',$track);
e4aa175a 249 } else {
250 $track->userid = $userid;
251 $track->scormid = $scormid;
252 $track->scoid = $scoid;
253 $track->attempt = $attempt;
254 $track->element = $element;
bf347041 255 $track->value = $value;
e4aa175a 256 $track->timemodified = time();
bf347041 257 $id = $DB->insert_record('scorm_scoes_track',$track);
e4aa175a 258 }
9528568b 259
d23121ab 260 // MDL-9552, update the gradebook everything raw score is sent
a0b36684 261 // Scoring by learning objects also needs to be included in the gradebook update
9528568b 262 if (strstr($element, '.score.raw') ||
a0b36684 263 (($element == 'cmi.core.lesson_status' || $element == 'cmi.completion_status') && ($track->value == 'completed' || $track->value == 'passed'))) {
264 $scorm = $DB->get_record('scorm', array('id' => $scormid));
265 $grademethod = $scorm->grademethod % 10;
266 if (strstr($element, '.score.raw') || $grademethod == GRADESCOES) {
267 include_once('lib.php');
268 scorm_update_grades($scorm, $userid);
269 }
d23121ab 270 }
9528568b 271
e4aa175a 272 return $id;
273}
274
e4aa175a 275function scorm_get_tracks($scoid,$userid,$attempt='') {
e4aa175a 276/// Gets all tracks of specified sco and user
bf347041 277 global $CFG, $DB;
e4aa175a 278
279 if (empty($attempt)) {
bf347041 280 if ($scormid = $DB->get_field('scorm_scoes','scorm', array('id'=>$scoid))) {
e4aa175a 281 $attempt = scorm_get_last_attempt($scormid,$userid);
282 } else {
283 $attempt = 1;
284 }
285 }
bf347041 286 if ($tracks = $DB->get_records('scorm_scoes_track', array('userid'=>$userid, 'scoid'=>$scoid, 'attempt'=>$attempt),'element ASC')) {
e4aa175a 287 $usertrack->userid = $userid;
9528568b 288 $usertrack->scoid = $scoid;
a30b6819 289 // Defined in order to unify scorm1.2 and scorm2004
e4aa175a 290 $usertrack->score_raw = '';
e4aa175a 291 $usertrack->status = '';
e4aa175a 292 $usertrack->total_time = '00:00:00';
293 $usertrack->session_time = '00:00:00';
294 $usertrack->timemodified = 0;
295 foreach ($tracks as $track) {
296 $element = $track->element;
297 $usertrack->{$element} = $track->value;
298 switch ($element) {
f69db63e 299 case 'cmi.core.lesson_status':
300 case 'cmi.completion_status':
301 if ($track->value == 'not attempted') {
302 $track->value = 'notattempted';
9528568b 303 }
f69db63e 304 $usertrack->status = $track->value;
9528568b 305 break;
e4aa175a 306 case 'cmi.core.score.raw':
307 case 'cmi.score.raw':
308 $usertrack->score_raw = $track->value;
9528568b 309 break;
e4aa175a 310 case 'cmi.core.session_time':
311 case 'cmi.session_time':
312 $usertrack->session_time = $track->value;
9528568b 313 break;
e4aa175a 314 case 'cmi.core.total_time':
315 case 'cmi.total_time':
316 $usertrack->total_time = $track->value;
9528568b 317 break;
318 }
e4aa175a 319 if (isset($track->timemodified) && ($track->timemodified > $usertrack->timemodified)) {
320 $usertrack->timemodified = $track->timemodified;
9528568b 321 }
3505e82b 322 }
9528568b 323 if (is_array($usertrack)) {
07b905ae 324 ksort($usertrack);
325 }
e4aa175a 326 return $usertrack;
327 } else {
328 return false;
329 }
330}
331
2b3447c3 332function scorm_get_user_data($userid) {
bf347041 333 global $DB;
2b3447c3 334/// Gets user info required to display the table of scorm results
335/// for report.php
e4aa175a 336
bf347041 337 return $DB->get_record('user', array('id'=>$userid),'firstname, lastname, picture');
2b3447c3 338}
e4aa175a 339
a30b6819 340function scorm_grade_user_attempt($scorm, $userid, $attempt=1, $time=false) {
bf347041 341 global $DB;
9528568b 342 $attemptscore = NULL;
a30b6819 343 $attemptscore->scoes = 0;
344 $attemptscore->values = 0;
345 $attemptscore->max = 0;
346 $attemptscore->sum = 0;
347 $attemptscore->lastmodify = 0;
9528568b 348
bf347041 349 if (!$scoes = $DB->get_records('scorm_scoes', array('scorm'=>$scorm->id))) {
a30b6819 350 return NULL;
e4aa175a 351 }
e4aa175a 352
7ce6eb87 353 // this treatment is necessary as the whatgrade field was not in the DB
354 // and so whatgrade and grademethod are combined in grademethod 10s are whatgrade
355 // and 1s are grademethod
a30b6819 356 $grademethod = $scorm->grademethod % 10;
357
9528568b 358 foreach ($scoes as $sco) {
2b3447c3 359 if ($userdata=scorm_get_tracks($sco->id, $userid,$attempt)) {
360 if (($userdata->status == 'completed') || ($userdata->status == 'passed')) {
a30b6819 361 $attemptscore->scoes++;
9528568b 362 }
2b3447c3 363 if (!empty($userdata->score_raw)) {
a30b6819 364 $attemptscore->values++;
365 $attemptscore->sum += $userdata->score_raw;
366 $attemptscore->max = ($userdata->score_raw > $attemptscore->max)?$userdata->score_raw:$attemptscore->max;
367 if (isset($userdata->timemodified) && ($userdata->timemodified > $attemptscore->lastmodify)) {
368 $attemptscore->lastmodify = $userdata->timemodified;
369 } else {
370 $attemptscore->lastmodify = 0;
371 }
9528568b 372 }
373 }
e4aa175a 374 }
2b3447c3 375 switch ($grademethod) {
a30b6819 376 case GRADEHIGHEST:
377 $score = $attemptscore->max;
9528568b 378 break;
a30b6819 379 case GRADEAVERAGE:
380 if ($attemptscore->values > 0) {
381 $score = $attemptscore->sum/$attemptscore->values;
5c1ac70c 382 } else {
a30b6819 383 $score = 0;
9528568b 384 }
385 break;
a30b6819 386 case GRADESUM:
387 $score = $attemptscore->sum;
9528568b 388 break;
a30b6819 389 case GRADESCOES:
390 $score = $attemptscore->scoes;
7ef16bf9 391 break;
392 default:
393 $score = $attemptscore->max; // Remote Learner GRADEHIGHEST is default
5c1ac70c 394 }
a30b6819 395
396 if ($time) {
397 $result = new stdClass();
398 $result->score = $score;
399 $result->time = $attemptscore->lastmodify;
400 } else {
401 $result = $score;
402 }
403
404 return $result;
405}
406
407function scorm_grade_user($scorm, $userid, $time=false) {
7ce6eb87 408 // this treatment is necessary as the whatgrade field was not in the DB
409 // and so whatgrade and grademethod are combined in grademethod 10s are whatgrade
410 // and 1s are grademethod
a30b6819 411 $whatgrade = intval($scorm->grademethod / 10);
412
7ce6eb87 413 // insure we dont grade user beyond $scorm->maxattempt settings
414 $lastattempt = scorm_get_last_attempt($scorm->id, $userid);
415 if($scorm->maxattempt != 0 && $lastattempt >= $scorm->maxattempt){
416 $lastattempt = $scorm->maxattempt;
417 }
418
a30b6819 419 switch ($whatgrade) {
420 case FIRSTATTEMPT:
421 return scorm_grade_user_attempt($scorm, $userid, 1, $time);
9528568b 422 break;
a30b6819 423 case LASTATTEMPT:
424 return scorm_grade_user_attempt($scorm, $userid, scorm_get_last_attempt($scorm->id, $userid), $time);
425 break;
426 case HIGHESTATTEMPT:
a30b6819 427 $maxscore = 0;
428 $attempttime = 0;
429 for ($attempt = 1; $attempt <= $lastattempt; $attempt++) {
430 $attemptscore = scorm_grade_user_attempt($scorm, $userid, $attempt, $time);
431 if ($time) {
432 if ($attemptscore->score > $maxscore) {
433 $maxscore = $attemptscore->score;
434 $attempttime = $attemptscore->time;
435 }
436 } else {
437 $maxscore = $attemptscore > $maxscore ? $attemptscore: $maxscore;
438 }
439 }
440 if ($time) {
441 $result = new stdClass();
442 $result->score = $maxscore;
443 $result->time = $attempttime;
444 return $result;
445 } else {
446 return $maxscore;
447 }
448 break;
449 case AVERAGEATTEMPT:
450 $lastattempt = scorm_get_last_attempt($scorm->id, $userid);
451 $sumscore = 0;
452 for ($attempt = 1; $attempt <= $lastattempt; $attempt++) {
453 $attemptscore = scorm_grade_user_attempt($scorm, $userid, $attempt, $time);
454 if ($time) {
455 $sumscore += $attemptscore->score;
456 } else {
457 $sumscore += $attemptscore;
458 }
459 }
460
461 if ($lastattempt > 0) {
462 $score = $sumscore / $lastattempt;
463 } else {
464 $score = 0;
465 }
466
467 if ($time) {
468 $result = new stdClass();
469 $result->score = $score;
470 $result->time = $attemptscore->time;
471 return $result;
472 } else {
473 return $score;
474 }
475 break;
476 }
e4aa175a 477}
478
8e45ba45 479function scorm_count_launchable($scormid,$organization='') {
bf347041 480 global $DB;
481
482 $sqlorganization = '';
483 $params = array($scormid);
8e45ba45 484 if (!empty($organization)) {
bf347041 485 $sqlorganization = " AND organization=?";
486 $params[] = $organization;
8e45ba45 487 }
6280b17a 488 $params []= ''; // empty launch
489 return $DB->count_records_select('scorm_scoes',"scorm = ? $sqlorganization AND launch <> ?", $params);
e4aa175a 490}
491
2b3447c3 492function scorm_get_last_attempt($scormid, $userid) {
bf347041 493 global $DB;
494
2b3447c3 495/// Find the last attempt number for the given user id and scorm id
bf347041 496 if ($lastattempt = $DB->get_record('scorm_scoes_track', array('userid'=>$userid, 'scormid'=>$scormid), 'max(attempt) as a')) {
2b3447c3 497 if (empty($lastattempt->a)) {
498 return '1';
499 } else {
500 return $lastattempt->a;
e4aa175a 501 }
502 }
e4aa175a 503}
504
e4aa175a 505function scorm_course_format_display($user,$course) {
bf347041 506 global $CFG, $DB;
e4aa175a 507
508 $strupdate = get_string('update');
509 $strmodule = get_string('modulename','scorm');
77bf0c29 510 $context = get_context_instance(CONTEXT_COURSE,$course->id);
e4aa175a 511
512 echo '<div class="mod-scorm">';
513 if ($scorms = get_all_instances_in_course('scorm', $course)) {
9528568b 514 // The module SCORM activity with the least id is the course
e4aa175a 515 $scorm = current($scorms);
516 if (! $cm = get_coursemodule_from_instance('scorm', $scorm->id, $course->id)) {
08b56f93 517 print_error('invalidcoursemodule');
e4aa175a 518 }
519 $colspan = '';
520 $headertext = '<table width="100%"><tr><td class="title">'.get_string('name').': <b>'.format_string($scorm->name).'</b>';
2b3447c3 521 if (has_capability('moodle/course:manageactivities', $context)) {
e4aa175a 522 if (isediting($course->id)) {
523 // Display update icon
524 $path = $CFG->wwwroot.'/course';
525 $headertext .= '<span class="commands">'.
526 '<a title="'.$strupdate.'" href="'.$path.'/mod.php?update='.$cm->id.'&amp;sesskey='.sesskey().'">'.
0d905d9f 527 '<img src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" alt="'.$strupdate.'" /></a></span>';
e4aa175a 528 }
529 $headertext .= '</td>';
530 // Display report link
bf347041 531 $trackedusers = $DB->get_record('scorm_scoes_track', array('scormid'=>$scorm->id), 'count(distinct(userid)) as c');
e4aa175a 532 if ($trackedusers->c > 0) {
533 $headertext .= '<td class="reportlink">'.
fa738731 534 '<a '.$CFG->frametarget.'" href="'.$CFG->wwwroot.'/mod/scorm/report.php?id='.$cm->id.'">'.
e4aa175a 535 get_string('viewallreports','scorm',$trackedusers->c).'</a>';
536 } else {
537 $headertext .= '<td class="reportlink">'.get_string('noreports','scorm');
538 }
539 $colspan = ' colspan="2"';
9528568b 540 }
e4aa175a 541 $headertext .= '</td></tr><tr><td'.$colspan.'>'.format_text(get_string('summary').':<br />'.$scorm->summary).'</td></tr></table>';
542 print_simple_box($headertext,'','100%');
543 scorm_view_display($user, $scorm, 'view.php?id='.$course->id, $cm, '100%');
544 } else {
0d699c24 545 if (has_capability('moodle/course:update', $context)) {
e4aa175a 546 // Create a new activity
2b3447c3 547 redirect($CFG->wwwroot.'/course/mod.php?id='.$course->id.'&amp;section=0&sesskey='.sesskey().'&amp;add=scorm');
e4aa175a 548 } else {
549 notify('Could not find a scorm course here');
550 }
551 }
552 echo '</div>';
553}
554
2b3447c3 555function scorm_view_display ($user, $scorm, $action, $cm, $boxwidth='') {
534792cd 556 global $CFG, $DB;
ab3b00e1 557
9528568b 558 if ($scorm->updatefreq == UPDATE_EVERYTIME) {
559 scorm_parse($scorm, false);
ab3b00e1 560 }
561
e4aa175a 562 $organization = optional_param('organization', '', PARAM_INT);
563
2b3447c3 564 print_simple_box_start('center',$boxwidth);
e4aa175a 565?>
29a43013 566 <div class="structurehead"><?php print_string('contents','scorm') ?></div>
e4aa175a 567<?php
568 if (empty($organization)) {
569 $organization = $scorm->launch;
570 }
07b905ae 571 if ($orgs = $DB->get_records_menu('scorm_scoes', array('scorm'=>$scorm->id, 'organization'=>'', 'launch'=>''), 'id', 'id,title')) {
e4aa175a 572 if (count($orgs) > 1) {
573 ?>
52a9a9b5 574 <div class='scorm-center'>
e4aa175a 575 <?php print_string('organizations','scorm') ?>
b7dc2256 576 <form id='changeorg' method='post' action='<?php echo $action ?>'>
e4aa175a 577 <?php choose_from_menu($orgs, 'organization', "$organization", '','submit()') ?>
578 </form>
579 </div>
580<?php
581 }
582 }
583 $orgidentifier = '';
b3659259 584 if ($sco = scorm_get_sco($organization, SCO_ONLY)) {
585 if (($sco->organization == '') && ($sco->launch == '')) {
586 $orgidentifier = $sco->identifier;
e4aa175a 587 } else {
b3659259 588 $orgidentifier = $sco->organization;
e4aa175a 589 }
590 }
28ffbff3 591
592/*
593 $orgidentifier = '';
bf347041 594 if ($org = $DB->get_record('scorm_scoes', array('id'=>$organization))) {
28ffbff3 595 if (($org->organization == '') && ($org->launch == '')) {
596 $orgidentifier = $org->identifier;
597 } else {
598 $orgidentifier = $org->organization;
599 }
600 }*/
601
2b3447c3 602 $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR)); // Just to be safe
dbe7e6f6 603 if (!file_exists($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'lib.php')) {
604 $scorm->version = 'scorm_12';
605 }
2b3447c3 606 require_once($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'lib.php');
607
e4aa175a 608 $result = scorm_get_toc($user,$scorm,'structlist',$orgidentifier);
609 $incomplete = $result->incomplete;
e4aa175a 610 echo $result->toc;
e4aa175a 611 print_simple_box_end();
28ffbff3 612
e4aa175a 613?>
52a9a9b5 614 <div class="scorm-center">
4675994a 615 <form id="theform" method="post" action="<?php echo $CFG->wwwroot ?>/mod/scorm/player.php">
e4aa175a 616 <?php
e4aa175a 617 if ($scorm->hidebrowse == 0) {
8949f8df 618 print_string('mode','scorm');
e4aa175a 619 echo ': <input type="radio" id="b" name="mode" value="browse" /><label for="b">'.get_string('browse','scorm').'</label>'."\n";
76ea4fb4 620 echo '<input type="radio" id="n" name="mode" value="normal" checked="checked" /><label for="n">'.get_string('normal','scorm')."</label>\n";
e4aa175a 621 } else {
76ea4fb4 622 echo '<input type="hidden" name="mode" value="normal" />'."\n";
e4aa175a 623 }
624 if (($incomplete === false) && (($result->attemptleft > 0)||($scorm->maxattempt == 0))) {
625?>
626 <br />
627 <input type="checkbox" id="a" name="newattempt" />
628 <label for="a"><?php print_string('newattempt','scorm') ?></label>
629<?php
630 }
631 ?>
632 <br />
4675994a 633 <input type="hidden" name="scoid"/>
df7ba610 634 <input type="hidden" name="id" value="<?php echo $cm->id ?>"/>
e4aa175a 635 <input type="hidden" name="currentorg" value="<?php echo $orgidentifier ?>" />
2b600d16 636 <input type="submit" value="<?php print_string('enter','scorm') ?>" />
e4aa175a 637 </form>
638 </div>
639<?php
640}
6280b17a 641
28ffbff3 642function scorm_simple_play($scorm,$user) {
bf347041 643 global $DB;
644
28ffbff3 645 $result = false;
9528568b 646
5b4b959b 647 $scoes = $DB->get_records_select('scorm_scoes', 'scorm = ? AND launch <> ?', array($scorm->id, $DB->sql_empty()));
9528568b 648
fa6eb1dc 649 if ($scoes && (count($scoes) == 1)) {
28ffbff3 650 if ($scorm->skipview >= 1) {
651 $sco = current($scoes);
652 if (scorm_get_tracks($sco->id,$user->id) === false) {
45698041 653 header('Location: player.php?a='.$scorm->id.'&scoid='.$sco->id);
28ffbff3 654 $result = true;
655 } else if ($scorm->skipview == 2) {
45698041 656 header('Location: player.php?a='.$scorm->id.'&scoid='.$sco->id);
28ffbff3 657 $result = true;
658 }
659 }
660 }
28ffbff3 661 return $result;
662}
663/*
8e45ba45 664function scorm_simple_play($scorm,$user) {
bf347041 665 global $DB;
8e45ba45 666 $result = false;
bf347041 667 if ($scoes = $DB->get_records_select('scorm_scoes','scorm=? AND launch<>""', array($scorm->id))) {
76ea4fb4 668 if (count($scoes) == 1) {
669 if ($scorm->skipview >= 1) {
670 $sco = current($scoes);
671 if (scorm_get_tracks($sco->id,$user->id) === false) {
672 header('Location: player.php?a='.$scorm->id.'&scoid='.$sco->id);
673 $result = true;
674 } else if ($scorm->skipview == 2) {
675 header('Location: player.php?a='.$scorm->id.'&scoid='.$sco->id);
676 $result = true;
677 }
8e45ba45 678 }
679 }
680 }
681 return $result;
682}
28ffbff3 683*/
d8c9d8a1 684
685function scorm_get_count_users($scormid, $groupingid=null) {
bf347041 686 global $CFG, $DB;
9528568b 687
d8c9d8a1 688 if (!empty($CFG->enablegroupings) && !empty($groupingid)) {
689 $sql = "SELECT COUNT(DISTINCT st.userid)
bf347041 690 FROM {scorm_scoes_track} st
691 INNER JOIN {groups_members} gm ON st.userid = gm.userid
9528568b 692 INNER JOIN {groupings_groups} gg ON gm.groupid = gg.groupid
bf347041 693 WHERE st.scormid = ? AND gg.groupingid = ?
d8c9d8a1 694 ";
bf347041 695 $params = array($scormid, $groupingid);
d8c9d8a1 696 } else {
697 $sql = "SELECT COUNT(DISTINCT st.userid)
9528568b 698 FROM {scorm_scoes_track} st
bf347041 699 WHERE st.scormid = ?
d8c9d8a1 700 ";
bf347041 701 $params = array($scormid);
d8c9d8a1 702 }
9528568b 703
bf347041 704 return ($DB->count_records_sql($sql, $params));
d8c9d8a1 705}
706
527af457 707/**
708* Build up the JavaScript representation of an array element
709*
710* @param string $sversion SCORM API version
711* @param array $userdata User track data
712* @param string $element_name Name of array element to get values for
713* @param array $children list of sub elements of this array element that also need instantiating
714* @return None
715*/
716function scorm_reconstitute_array_element($sversion, $userdata, $element_name, $children) {
717 // reconstitute comments_from_learner and comments_from_lms
718 $current = '';
719 $count = 0;
720
721 // filter out the ones we want
722 $element_list = array();
723 foreach($userdata as $element => $value){
724 if (substr($element,0,strlen($element_name)) == $element_name) {
725 $element_list[$element] = $value;
726 }
727 }
728
729 // sort elements in .n array order
730 uksort($element_list, "scorm_element_cmp");
731
732 // generate JavaScript
733 foreach($element_list as $element => $value){
734 if ($sversion == 'scorm_13') {
735 $element = preg_replace('/\.(\d+)\./', ".N\$1.", $element);
736 preg_match('/\.(N\d+)\./', $element, $matches);
737 } else {
738 $element = preg_replace('/\.(\d+)\./', "_\$1.", $element);
739 preg_match('/\_(\d+)\./', $element, $matches);
740 }
741 if (count($matches) > 0 && $current != $matches[1]) {
742 $current = $matches[1];
743 $count++;
744 $end = strpos($element,$matches[1])+strlen($matches[1]);
745 $subelement = substr($element,0,$end);
746 echo ' '.$subelement." = new Object();\n";
747 // now add the children
748 foreach ($children as $child) {
749 echo ' '.$subelement.".".$child." = new Object();\n";
750 echo ' '.$subelement.".".$child."._children = ".$child."_children;\n";
751 }
752 }
753 echo ' '.$element.' = \''.$value."';\n";
754 }
755 if ($count > 0) {
756 echo ' '.$element_name.'._count = '.$count.";\n";
757 }
758}
759
760/**
761* Build up the JavaScript representation of an array element
762*
763* @param string $a left array element
764* @param string $b right array element
765* @return comparator - 0,1,-1
766*/
767function scorm_element_cmp($a, $b) {
768 preg_match('/(\d+)\./', $a, $matches);
769 $left = intval($matches[1]);
770 preg_match('/(\d+)\./', $b, $matches);
771 $right = intval($matches[1]);
772 if ($left < $right) {
773 return -1; // smaller
774 } elseif ($left > $right) {
775 return 1; // bigger
776 } else {
777 return 0; // equal to
778 }
779}
780?>