mod lib MDL-19294 Added boilerplate and phpdocs
[moodle.git] / mod / scorm / lib.php
CommitLineData
e4aa175a 1<?php // $Id$
2
9528568b 3define('SCORM_TYPE_LOCAL', 'local');
4define('SCORM_TYPE_LOCALSYNC', 'localsync');
5define('SCORM_TYPE_EXTERNAL', 'external');
6define('SCORM_TYPE_IMSREPOSITORY', 'imsrepository');
7
8
e4aa175a 9/**
10* Given an object containing all the necessary data,
7cac0c4b 11* (defined by the form in mod_form.php) this function
e4aa175a 12* will create a new instance and return the id number
13* of the new instance.
14*
9528568b 15* @param object $scorm Form data
16* @param object $mform
17* @return int new instance id
e4aa175a 18*/
9528568b 19
20function scorm_add_instance($scorm, $mform=null) {
c18269c7 21 global $CFG, $DB;
a679d64d 22
23 require_once('locallib.php');
24
d54e2145 25 if (empty($scorm->timerestrict)) {
26 $scorm->timeopen = 0;
27 $scorm->timeclose = 0;
28 }
29
9528568b 30 $cmid = $scorm->coursemodule;
31 $cmidnumber = $scorm->cmidnumber;
32 $courseid = $scorm->course;
76ea4fb4 33
9528568b 34 $context = get_context_instance(CONTEXT_MODULE, $cmid);
a679d64d 35
9528568b 36 $scorm = scorm_option2text($scorm);
37 $scorm->width = (int)str_replace('%', '', $scorm->width);
38 $scorm->height = (int)str_replace('%', '', $scorm->height);
e4aa175a 39
9528568b 40 if (!isset($scorm->whatgrade)) {
41 $scorm->whatgrade = 0;
42 }
43 $scorm->grademethod = ($scorm->whatgrade * 10) + $scorm->grademethod;
b3659259 44
9528568b 45 if (!$id = $DB->insert_record('scorm', $scorm)) {
46 return false;
47 }
e4aa175a 48
9528568b 49/// update course module record - from now on this instance properly exists and all function may be used
50 if (!$DB->set_field('course_modules', 'instance', $id, array('id'=>$cmid))) {
51 print_error('cannotaddcoursemodule');
52 }
e4aa175a 53
9528568b 54/// reload scorm instance
55 $scorm = $DB->get_record('scorm', array('id'=>$id));
56
57/// store the package and verify
58 if ($scorm->scormtype === SCORM_TYPE_LOCAL) {
59 if ($mform) {
60 $filename = $mform->get_new_filename('packagefile');
61 if ($filename !== false) {
62 $fs = get_file_storage();
63 $fs->delete_area_files($context->id, 'scorm_package');
64 $mform->save_stored_file('packagefile', $context->id, 'scorm_package', 0, '/', $filename);
65 $scorm->reference = $filename;
8ba4f1e0 66 }
e4aa175a 67 }
68
9528568b 69 } else if ($scorm->scormtype === SCORM_TYPE_LOCALSYNC) {
70 $scorm->reference = $scorm->packageurl;
e4aa175a 71
9528568b 72 } else if ($scorm->scormtype === SCORM_TYPE_EXTERNAL) {
73 $scorm->reference = $scorm->packageurl;
74
75 } else if ($scorm->scormtype === SCORM_TYPE_IMSREPOSITORY) {
76 $scorm->reference = $scorm->packageurl;
531fa830 77
a679d64d 78 } else {
9528568b 79 return false;
e4aa175a 80 }
9528568b 81
82 // save reference
83 $DB->update_record('scorm', $scorm);
84
85
86/// extra fields required in grade related functions
87 $scorm->course = $courseid;
88 $scorm->cmidnumber = $cmidnumber;
89 $scorm->cmid = $cmid;
90
91 scorm_parse($scorm, true);
92
93 scorm_grade_item_update($scorm);
94
95 return $scorm->id;
e4aa175a 96}
97
98/**
99* Given an object containing all the necessary data,
7cac0c4b 100* (defined by the form in mod_form.php) this function
e4aa175a 101* will update an existing instance with new data.
102*
9528568b 103* @param object $scorm Form data
104* @param object $mform
105* @return bool success
e4aa175a 106*/
9528568b 107function scorm_update_instance($scorm, $mform=null) {
c18269c7 108 global $CFG, $DB;
e4aa175a 109
a679d64d 110 require_once('locallib.php');
76ea4fb4 111
d54e2145 112 if (empty($scorm->timerestrict)) {
113 $scorm->timeopen = 0;
114 $scorm->timeclose = 0;
115 }
116
9528568b 117 $cmid = $scorm->coursemodule;
118 $cmidnumber = $scorm->cmidnumber;
119 $courseid = $scorm->course;
120
121 $scorm->id = $scorm->instance;
122
123 $context = get_context_instance(CONTEXT_MODULE, $cmid);
124
125 if ($scorm->scormtype === SCORM_TYPE_LOCAL) {
126 if ($mform) {
127 $filename = $mform->get_new_filename('packagefile');
128 if ($filename !== false) {
129 $scorm->reference = $filename;
130 $fs = get_file_storage();
131 $fs->delete_area_files($context->id, 'scorm_package');
132 $mform->save_stored_file('packagefile', $context->id, 'scorm_package', 0, '/', $filename);
a679d64d 133 }
76ea4fb4 134 }
76ea4fb4 135
9528568b 136 } else if ($scorm->scormtype === SCORM_TYPE_LOCALSYNC) {
137 $scorm->reference = $scorm->packageurl;
138
139 } else if ($scorm->scormtype === SCORM_TYPE_EXTERNAL) {
140 $scorm->reference = $scorm->packageurl;
141
142 } else if ($scorm->scormtype === SCORM_TYPE_IMSREPOSITORY) {
143 $scorm->reference = $scorm->packageurl;
144
145 } else {
146 return false;
147 }
bfe8c2f0 148
e4aa175a 149 $scorm = scorm_option2text($scorm);
9528568b 150 $scorm->width = (int)str_replace('%','',$scorm->width);
151 $scorm->height = (int)str_replace('%','',$scorm->height);
152 $scorm->timemodified = time();
e4aa175a 153
b3659259 154 if (!isset($scorm->whatgrade)) {
155 $scorm->whatgrade = 0;
156 }
9528568b 157 $scorm->grademethod = ($scorm->whatgrade * 10) + $scorm->grademethod;
a30b6819 158
9528568b 159 if (!$DB->update_record('scorm', $scorm)) {
160 return false;
531fa830 161 }
162
9528568b 163 $scorm = $DB->get_record('scorm', array('id'=>$scorm->id));
164
165/// extra fields required in grade related functions
166 $scorm->course = $courseid;
167 $scorm->idnumber = $cmidnumber;
168 $scorm->cmid = $cmid;
169
170 scorm_parse($scorm, (bool)$scorm->updatefreq);
171
172 scorm_grade_item_update($scorm);
173
174 return true;
e4aa175a 175}
176
177/**
178* Given an ID of an instance of this module,
179* this function will permanently delete the instance
180* and any data that depends on it.
181*
182* @param int $id Scorm instance id
183* @return boolean
184*/
185function scorm_delete_instance($id) {
c18269c7 186 global $CFG, $DB;
e4aa175a 187
c18269c7 188 if (! $scorm = $DB->get_record('scorm', array('id'=>$id))) {
e4aa175a 189 return false;
190 }
191
192 $result = true;
193
e4aa175a 194 // Delete any dependent records
c18269c7 195 if (! $DB->delete_records('scorm_scoes_track', array('scormid'=>$scorm->id))) {
e4aa175a 196 $result = false;
197 }
c18269c7 198 if ($scoes = $DB->get_records('scorm_scoes', array('scorm'=>$scorm->id))) {
b3659259 199 foreach ($scoes as $sco) {
c18269c7 200 if (! $DB->delete_records('scorm_scoes_data', array('scoid'=>$sco->id))) {
b3659259 201 $result = false;
202 }
9528568b 203 }
c18269c7 204 $DB->delete_records('scorm_scoes', array('scorm'=>$scorm->id));
b3659259 205 } else {
e4aa175a 206 $result = false;
207 }
c18269c7 208 if (! $DB->delete_records('scorm', array('id'=>$scorm->id))) {
e4aa175a 209 $result = false;
210 }
a30b6819 211
c18269c7 212 /*if (! $DB->delete_records('scorm_sequencing_controlmode', array('scormid'=>$scorm->id))) {
e4aa175a 213 $result = false;
214 }
c18269c7 215 if (! $DB->delete_records('scorm_sequencing_rolluprules', array('scormid'=>$scorm->id))) {
e4aa175a 216 $result = false;
217 }
c18269c7 218 if (! $DB->delete_records('scorm_sequencing_rolluprule', array('scormid'=>$scorm->id))) {
e4aa175a 219 $result = false;
220 }
c18269c7 221 if (! $DB->delete_records('scorm_sequencing_rollupruleconditions', array('scormid'=>$scorm->id))) {
e4aa175a 222 $result = false;
223 }
c18269c7 224 if (! $DB->delete_records('scorm_sequencing_rolluprulecondition', array('scormid'=>$scorm->id))) {
e4aa175a 225 $result = false;
226 }
c18269c7 227 if (! $DB->delete_records('scorm_sequencing_rulecondition', array('scormid'=>$scorm->id))) {
e4aa175a 228 $result = false;
229 }
c18269c7 230 if (! $DB->delete_records('scorm_sequencing_ruleconditions', array('scormid'=>$scorm->id))) {
e4aa175a 231 $result = false;
9528568b 232 }*/
531fa830 233
c18269c7 234 scorm_grade_item_delete($scorm);
9528568b 235
e4aa175a 236 return $result;
237}
238
239/**
240* Return a small object with summary information about what a
241* user has done with a given particular instance of this module
242* Used for user activity reports.
243*
244* @param int $course Course id
245* @param int $user User id
9528568b 246* @param int $mod
e4aa175a 247* @param int $scorm The scorm id
248* @return mixed
249*/
9528568b 250function scorm_user_outline($course, $user, $mod, $scorm) {
531fa830 251 global $CFG;
a30b6819 252 require_once('locallib.php');
253
254 $return = scorm_grade_user($scorm, $user->id, true);
255
e4aa175a 256 return $return;
257}
258
259/**
260* Print a detailed representation of what a user has done with
261* a given particular instance of this module, for user activity reports.
262*
263* @param int $course Course id
264* @param int $user User id
9528568b 265* @param int $mod
e4aa175a 266* @param int $scorm The scorm id
267* @return boolean
268*/
269function scorm_user_complete($course, $user, $mod, $scorm) {
bf347041 270 global $CFG, $DB;
e4aa175a 271
272 $liststyle = 'structlist';
273 $scormpixdir = $CFG->modpixpath.'/scorm/pix';
274 $now = time();
275 $firstmodify = $now;
276 $lastmodify = 0;
277 $sometoreport = false;
278 $report = '';
9528568b 279
bf347041 280 if ($orgs = $DB->get_records('scorm_scoes', array('scorm'=>$scorm->id, 'organization'=>'', 'launch'=>''),'id','id,identifier,title')) {
e4aa175a 281 if (count($orgs) <= 1) {
282 unset($orgs);
283 $orgs[]->identifier = '';
284 }
285 $report .= '<div class="mod-scorm">'."\n";
286 foreach ($orgs as $org) {
bf347041 287 $conditions = array();
e4aa175a 288 $currentorg = '';
289 if (!empty($org->identifier)) {
290 $report .= '<div class="orgtitle">'.$org->title.'</div>';
291 $currentorg = $org->identifier;
bf347041 292 $conditions['organization'] = $currentorg;
e4aa175a 293 }
294 $report .= "<ul id='0' class='$liststyle'>";
bf347041 295 $conditions['scorm'] = $scorm->id;
296 if ($scoes = $DB->get_records('scorm_scoes', $conditions, "id ASC")){
9fb2de4e 297 // drop keys so that we can access array sequentially
9528568b 298 $scoes = array_values($scoes);
e4aa175a 299 $level=0;
300 $sublist=1;
301 $parents[$level]='/';
9fb2de4e 302 foreach ($scoes as $pos=>$sco) {
e4aa175a 303 if ($parents[$level]!=$sco->parent) {
304 if ($level>0 && $parents[$level-1]==$sco->parent) {
305 $report .= "\t\t</ul></li>\n";
306 $level--;
307 } else {
308 $i = $level;
309 $closelist = '';
310 while (($i > 0) && ($parents[$level] != $sco->parent)) {
311 $closelist .= "\t\t</ul></li>\n";
312 $i--;
313 }
314 if (($i == 0) && ($sco->parent != $currentorg)) {
315 $report .= "\t\t<li><ul id='$sublist' class='$liststyle'>\n";
316 $level++;
317 } else {
318 $report .= $closelist;
319 $level = $i;
320 }
321 $parents[$level]=$sco->parent;
322 }
323 }
324 $report .= "\t\t<li>";
9fb2de4e 325 if (isset($scoes[$pos+1])) {
326 $nextsco = $scoes[$pos+1];
327 } else {
328 $nextsco = false;
329 }
e4aa175a 330 if (($nextsco !== false) && ($sco->parent != $nextsco->parent) && (($level==0) || (($level>0) && ($nextsco->parent == $sco->identifier)))) {
331 $sublist++;
332 } else {
7150b8ae 333 $report .= '<img src="'.$scormpixdir.'/spacer.gif" alt="" />';
e4aa175a 334 }
335
336 if ($sco->launch) {
337 require_once('locallib.php');
338 $score = '';
339 $totaltime = '';
340 if ($usertrack=scorm_get_tracks($sco->id,$user->id)) {
341 if ($usertrack->status == '') {
342 $usertrack->status = 'notattempted';
343 }
344 $strstatus = get_string($usertrack->status,'scorm');
345 $report .= "<img src='".$scormpixdir.'/'.$usertrack->status.".gif' alt='$strstatus' title='$strstatus' />";
346 if ($usertrack->timemodified != 0) {
347 if ($usertrack->timemodified > $lastmodify) {
348 $lastmodify = $usertrack->timemodified;
349 }
350 if ($usertrack->timemodified < $firstmodify) {
351 $firstmodify = $usertrack->timemodified;
352 }
353 }
354 } else {
355 if ($sco->scormtype == 'sco') {
356 $report .= '<img src="'.$scormpixdir.'/'.'notattempted.gif" alt="'.get_string('notattempted','scorm').'" title="'.get_string('notattempted','scorm').'" />';
357 } else {
358 $report .= '<img src="'.$scormpixdir.'/'.'asset.gif" alt="'.get_string('asset','scorm').'" title="'.get_string('asset','scorm').'" />';
359 }
360 }
361 $report .= "&nbsp;$sco->title $score$totaltime</li>\n";
362 if ($usertrack !== false) {
363 $sometoreport = true;
364 $report .= "\t\t\t<li><ul class='$liststyle'>\n";
365 foreach($usertrack as $element => $value) {
366 if (substr($element,0,3) == 'cmi') {
367 $report .= '<li>'.$element.' => '.$value.'</li>';
368 }
369 }
370 $report .= "\t\t\t</ul></li>\n";
9528568b 371 }
e4aa175a 372 } else {
373 $report .= "&nbsp;$sco->title</li>\n";
374 }
375 }
376 for ($i=0;$i<$level;$i++) {
377 $report .= "\t\t</ul></li>\n";
378 }
379 }
380 $report .= "\t</ul><br />\n";
381 }
382 $report .= "</div>\n";
383 }
384 if ($sometoreport) {
385 if ($firstmodify < $now) {
386 $timeago = format_time($now - $firstmodify);
387 echo get_string('firstaccess','scorm').': '.userdate($firstmodify).' ('.$timeago.")<br />\n";
388 }
389 if ($lastmodify > 0) {
390 $timeago = format_time($now - $lastmodify);
391 echo get_string('lastaccess','scorm').': '.userdate($lastmodify).' ('.$timeago.")<br />\n";
392 }
393 echo get_string('report','scorm').":<br />\n";
394 echo $report;
395 } else {
dabfd0ed 396 print_string('noactivity','scorm');
e4aa175a 397 }
398
399 return true;
400}
401
e4aa175a 402/**
403* Function to be run periodically according to the moodle cron
404* This function searches for things that need to be done, such
405* as sending out mail, toggling flags etc ...
406*
407* @return boolean
408*/
409function scorm_cron () {
bf347041 410 global $CFG, $DB;
a679d64d 411
412 require_once('locallib.php');
413
414 $sitetimezone = $CFG->timezone;
9528568b 415 /// Now see if there are any scorm updates to be done
416
bfe8c2f0 417 if (!isset($CFG->scorm_updatetimelast)) { // To catch the first time
418 set_config('scorm_updatetimelast', 0);
419 }
420
a679d64d 421 $timenow = time();
8f54becc 422 $updatetime = usergetmidnight($timenow, $sitetimezone) + ($CFG->scorm_updatetimelast * 3600);
a679d64d 423
424 if ($CFG->scorm_updatetimelast < $updatetime and $timenow > $updatetime) {
425
bfe8c2f0 426 set_config('scorm_updatetimelast', $timenow);
e4aa175a 427
376c9c70 428 mtrace('Updating scorm packages which require daily update');//We are updating
bfe8c2f0 429
bf347041 430 $scormsupdate = $DB->get_records('scorm', array('updatefreq'=>UPDATE_EVERYDAY));
9528568b 431 foreach($scormsupdate as $scormupdate) {
432 scorm_parse($scormupdate, true);
a679d64d 433 }
434 }
435
e4aa175a 436 return true;
437}
438
439/**
531fa830 440 * Return grade for given user or all users.
441 *
442 * @param int $scormid id of scorm
443 * @param int $userid optional user id, 0 means all users
444 * @return array array of grades, false if none
445 */
446function scorm_get_user_grades($scorm, $userid=0) {
bf347041 447 global $CFG, $DB;
531fa830 448 require_once('locallib.php');
449
450 $grades = array();
451 if (empty($userid)) {
bf347041 452 if ($scousers = $DB->get_records_select('scorm_scoes_track', "scormid=? GROUP BY userid", array($scorm->id), "", "userid,null")) {
531fa830 453 foreach ($scousers as $scouser) {
454 $grades[$scouser->userid] = new object();
455 $grades[$scouser->userid]->id = $scouser->userid;
456 $grades[$scouser->userid]->userid = $scouser->userid;
457 $grades[$scouser->userid]->rawgrade = scorm_grade_user($scorm, $scouser->userid);
458 }
459 } else {
460 return false;
461 }
e4aa175a 462
531fa830 463 } else {
bf347041 464 if (!$DB->get_records_select('scorm_scoes_track', "scormid=? AND userid=? GROUP BY userid", array($scorm->id, $userid), "", "userid,null")) {
531fa830 465 return false; //no attempt yet
466 }
467 $grades[$userid] = new object();
468 $grades[$userid]->id = $userid;
469 $grades[$userid]->userid = $userid;
470 $grades[$userid]->rawgrade = scorm_grade_user($scorm, $userid);
e4aa175a 471 }
e4aa175a 472
531fa830 473 return $grades;
474}
475
476/**
477 * Update grades in central gradebook
478 *
775f811a 479 * @param object $scorm
531fa830 480 * @param int $userid specific user only, 0 mean all
481 */
775f811a 482function scorm_update_grades($scorm, $userid=0, $nullifnone=true) {
bf347041 483 global $CFG, $DB;
775f811a 484 require_once($CFG->libdir.'/gradelib.php');
531fa830 485
775f811a 486 if ($grades = scorm_get_user_grades($scorm, $userid)) {
487 scorm_grade_item_update($scorm, $grades);
531fa830 488
775f811a 489 } else if ($userid and $nullifnone) {
490 $grade = new object();
491 $grade->userid = $userid;
492 $grade->rawgrade = NULL;
493 scorm_grade_item_update($scorm, $grade);
531fa830 494
e4aa175a 495 } else {
775f811a 496 scorm_grade_item_update($scorm);
497 }
498}
499
500/**
501 * Update all grades in gradebook.
502 */
503function scorm_upgrade_grades() {
504 global $DB;
505
506 $sql = "SELECT COUNT('x')
507 FROM {scorm} s, {course_modules} cm, {modules} m
508 WHERE m.name='scorm' AND m.id=cm.module AND cm.instance=s.id";
509 $count = $DB->count_records_sql($sql);
510
511 $sql = "SELECT s.*, cm.idnumber AS cmidnumber, s.course AS courseid
512 FROM {scorm} s, {course_modules} cm, {modules} m
513 WHERE m.name='scorm' AND m.id=cm.module AND cm.instance=s.id";
514 if ($rs = $DB->get_recordset_sql($sql)) {
775f811a 515 $pbar = new progress_bar('scormupgradegrades', 500, true);
516 $i=0;
517 foreach ($rs as $scorm) {
518 $i++;
519 upgrade_set_timeout(60*5); // set up timeout, may also abort execution
520 scorm_update_grades($scorm, 0, false);
521 $pbar->update($i, $count, "Updating Scorm grades ($i/$count).");
531fa830 522 }
775f811a 523 $rs->close();
e4aa175a 524 }
531fa830 525}
e4aa175a 526
531fa830 527/**
528 * Update/create grade item for given scorm
529 *
530 * @param object $scorm object with extra cmidnumber
0b5a80a1 531 * @param mixed optional array/object of grade(s); 'reset' means reset grades in gradebook
531fa830 532 * @return object grade_item
533 */
0b5a80a1 534function scorm_grade_item_update($scorm, $grades=NULL) {
bf347041 535 global $CFG, $DB;
531fa830 536 if (!function_exists('grade_update')) { //workaround for buggy PHP versions
537 require_once($CFG->libdir.'/gradelib.php');
538 }
539
7ef16bf9 540 $params = array('itemname'=>$scorm->name);
541 if (isset($scorm->cmidnumber)) {
542 $params['idnumber'] = $scorm->cmidnumber;
543 }
9528568b 544
531fa830 545 if (($scorm->grademethod % 10) == 0) { // GRADESCOES
5b4b959b 546 if ($maxgrade = $DB->count_records_select('scorm_scoes', 'scorm = ? AND launch <> ?', array($scorm->id, $DB->sql_empty()))) {
531fa830 547 $params['gradetype'] = GRADE_TYPE_VALUE;
548 $params['grademax'] = $maxgrade;
549 $params['grademin'] = 0;
550 } else {
551 $params['gradetype'] = GRADE_TYPE_NONE;
e4aa175a 552 }
531fa830 553 } else {
554 $params['gradetype'] = GRADE_TYPE_VALUE;
555 $params['grademax'] = $scorm->maxgrade;
556 $params['grademin'] = 0;
e4aa175a 557 }
531fa830 558
0b5a80a1 559 if ($grades === 'reset') {
560 $params['reset'] = true;
561 $grades = NULL;
562 }
563
564 return grade_update('mod/scorm', $scorm->course, 'mod', 'scorm', $scorm->id, 0, $grades, $params);
531fa830 565}
566
567/**
568 * Delete grade item for given scorm
569 *
570 * @param object $scorm object
571 * @return object grade_item
572 */
573function scorm_grade_item_delete($scorm) {
574 global $CFG;
575 require_once($CFG->libdir.'/gradelib.php');
576
577 return grade_update('mod/scorm', $scorm->course, 'mod', 'scorm', $scorm->id, 0, NULL, array('deleted'=>1));
e4aa175a 578}
579
580function scorm_get_view_actions() {
581 return array('pre-view','view','view all','report');
582}
583
584function scorm_get_post_actions() {
585 return array();
586}
587
e4aa175a 588function scorm_option2text($scorm) {
1adc77e6 589 $scorm_popoup_options = scorm_get_popup_options_array();
590
e4aa175a 591 if (isset($scorm->popup)) {
76ea4fb4 592 if ($scorm->popup == 1) {
e4aa175a 593 $optionlist = array();
1adc77e6 594 foreach ($scorm_popoup_options as $name => $option) {
e4aa175a 595 if (isset($scorm->$name)) {
596 $optionlist[] = $name.'='.$scorm->$name;
597 } else {
598 $optionlist[] = $name.'=0';
599 }
9528568b 600 }
e4aa175a 601 $scorm->options = implode(',', $optionlist);
602 } else {
603 $scorm->options = '';
9528568b 604 }
e4aa175a 605 } else {
606 $scorm->popup = 0;
607 $scorm->options = '';
608 }
609 return $scorm;
610}
611
0b5a80a1 612/**
613 * Implementation of the function for printing the form elements that control
614 * whether the course reset functionality affects the scorm.
615 * @param $mform form passed by reference
616 */
617function scorm_reset_course_form_definition(&$mform) {
618 $mform->addElement('header', 'scormheader', get_string('modulenameplural', 'scorm'));
619 $mform->addElement('advcheckbox', 'reset_scorm', get_string('deleteallattempts','scorm'));
620}
621
622/**
623 * Course reset form defaults.
624 */
625function scorm_reset_course_form_defaults($course) {
626 return array('reset_scorm'=>1);
627}
628
629/**
630 * Removes all grades from gradebook
631 * @param int $courseid
632 * @param string optional type
633 */
634function scorm_reset_gradebook($courseid, $type='') {
bf347041 635 global $CFG, $DB;
0b5a80a1 636
637 $sql = "SELECT s.*, cm.idnumber as cmidnumber, s.course as courseid
bf347041 638 FROM {scorm} s, {course_modules} cm, {modules} m
639 WHERE m.name='scorm' AND m.id=cm.module AND cm.instance=s.id AND s.course=?";
0b5a80a1 640
bf347041 641 if ($scorms = $DB->get_records_sql($sql, array($courseid))) {
0b5a80a1 642 foreach ($scorms as $scorm) {
643 scorm_grade_item_update($scorm, 'reset');
644 }
645 }
646}
647
648/**
649 * Actual implementation of the rest coures functionality, delete all the
650 * scorm attempts for course $data->courseid.
651 * @param $data the data submitted from the reset course.
652 * @return array status array
653 */
654function scorm_reset_userdata($data) {
bf347041 655 global $CFG, $DB;
0b5a80a1 656
657 $componentstr = get_string('modulenameplural', 'scorm');
658 $status = array();
659
660 if (!empty($data->reset_scorm)) {
661 $scormssql = "SELECT s.id
bf347041 662 FROM {scorm} s
663 WHERE s.course=?";
0b5a80a1 664
bf347041 665 $DB->delete_records_select('scorm_scoes_track', "scormid IN ($scormssql)", array($data->courseid));
0b5a80a1 666
667 // remove all grades from gradebook
668 if (empty($data->reset_gradebook_grades)) {
669 scorm_reset_gradebook($data->courseid);
670 }
671
672 $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallattempts', 'scorm'), 'error'=>false);
673 }
674
675 // no dates to shift here
676
677 return $status;
678}
679
f432bebf 680/**
681 * Returns all other caps used in module
682 */
683function scorm_get_extra_capabilities() {
684 return array('moodle/site:accessallgroups');
685}
686
9528568b 687/**
688 * Lists all file areas current user may browse
689 */
690function scorm_get_file_areas($course, $cm, $context) {
691 $areas = array();
692 if (has_capability('moodle/course:managefiles', $context)) {
9528568b 693 $areas['scorm_content'] = get_string('areacontent', 'scorm');
694 $areas['scorm_package'] = get_string('areapackage', 'scorm');
695 }
696 return $areas;
697}
698
699/**
700 * File browsing support
701 */
702function scorm_get_file_info($browser, $areas, $course, $cm, $context, $filearea, $itemid, $filepath, $filename) {
703 global $CFG;
704
705 if (!has_capability('moodle/course:managefiles', $context)) {
706 return null;
707 }
708
709 // no writing for now!
710
711 $fs = get_file_storage();
712
713 if ($filearea === 'scorm_content') {
714
715 $filepath = is_null($filepath) ? '/' : $filepath;
716 $filename = is_null($filename) ? '.' : $filename;
717
718 $urlbase = $CFG->wwwroot.'/pluginfile.php';
719 if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
720 if ($filepath === '/' and $filename === '.') {
721 $storedfile = new virtual_root_file($context->id, $filearea, 0);
722 } else {
723 // not found
724 return null;
725 }
726 }
727 class scorm_package_file_info extends file_info_stored {
728 public function get_parent() {
729 if ($this->lf->get_filepath() === '/' and $this->lf->get_filename() === '.') {
730 return $this->browser->get_file_info($this->context);
731 }
732 return parent::get_parent();
733 }
734 public function get_visible_name() {
735 if ($this->lf->get_filepath() === '/' and $this->lf->get_filename() === '.') {
3156b8ca 736 return $this->topvisiblename;
9528568b 737 }
738 return parent::get_visible_name();
739 }
740 }
8546def3 741 return new scorm_package_file_info($browser, $context, $storedfile, $urlbase, $areas[$filearea], true, true, false, false);
9528568b 742
743 } else if ($filearea === 'scorm_package') {
744 $filepath = is_null($filepath) ? '/' : $filepath;
745 $filename = is_null($filename) ? '.' : $filename;
746
747 $urlbase = $CFG->wwwroot.'/pluginfile.php';
748 if (!$storedfile = $fs->get_file($context->id, $filearea, 0, $filepath, $filename)) {
749 if ($filepath === '/' and $filename === '.') {
750 $storedfile = new virtual_root_file($context->id, $filearea, 0);
751 } else {
752 // not found
753 return null;
754 }
755 }
756 return new file_info_stored($browser, $context, $storedfile, $urlbase, $areas[$filearea], false, true, false);
757 }
758
759 // scorm_intro handled in file_browser
760
761 return false;
762}
763
764/**
765 * Serves scorm content, introduction images and packages. Implements needed access control ;-)
766 */
767function scorm_pluginfile($course, $cminfo, $context, $filearea, $args) {
768 global $CFG;
769
770 if (!$cminfo->uservisible) {
771 return false; // probably hidden
772 }
773
774 $lifetime = isset($CFG->filelifetime) ? $CFG->filelifetime : 86400;
775
ac3668bf 776 if ($filearea === 'scorm_content') {
9528568b 777 $revision = (int)array_shift($args); // prevents caching problems - ignored here
778 $relativepath = '/'.implode('/', $args);
779 $fullpath = $context->id.'scorm_content0'.$relativepath;
780 // TODO: add any other access restrictions here if needed!
781
782 } else if ($filearea === 'scorm_package') {
783 if (!has_capability('moodle/course:manageactivities', $context)) {
784 return false;
785 }
786 $relativepath = '/'.implode('/', $args);
787 $fullpath = $context->id.'scorm_package0'.$relativepath;
788 $lifetime = 0; // no caching here
789
790 } else {
791 return false;
792 }
793
794 $fs = get_file_storage();
795 if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
796 return false;
797 }
798
799 // finally send the file
800 send_stored_file($file, $lifetime, 0, false);
801}
802
42f103be 803/**
804 * @param string $feature FEATURE_xx constant for requested feature
805 * @return mixed True if module supports feature, null if doesn't know
806 */
807function scorm_supports($feature) {
808 switch($feature) {
809 case FEATURE_GROUPS: return false;
810 case FEATURE_GROUPINGS: return false;
811 case FEATURE_GROUPMEMBERSONLY: return true;
dc5c2bd9 812 case FEATURE_MOD_INTRO: return true;
42f103be 813 case FEATURE_COMPLETION_TRACKS_VIEWS: return true;
814 case FEATURE_GRADE_HAS_GRADE: return true;
815 case FEATURE_GRADE_OUTCOMES: return true;
816
817 default: return null;
818 }
819}
820