SCORM MDL-21568 fix regression
[moodle.git] / mod / scorm / db / upgrade.php
1 <?php
3 // This file keeps track of upgrades to
4 // the scorm module
5 //
6 // Sometimes, changes between versions involve
7 // alterations to database structures and other
8 // major things that may break installations.
9 //
10 // The upgrade function in this file will attempt
11 // to perform all the necessary actions to upgrade
12 // your older installation to the current version.
13 //
14 // If there's something it cannot do itself, it
15 // will tell you what you need to do.
16 //
17 // The commands in here will all be database-neutral,
18 // using the methods of database_manager class
19 //
20 // Please do not forget to use upgrade_set_timeout()
21 // before any action that may take longer time to finish.
23 function xmldb_scorm_upgrade($oldversion) {
24     global $CFG, $DB;
26     $dbman = $DB->get_manager();
28 //===== 1.9.0 upgrade line ======//
30     // Adding missing 'whatgrade' field to table scorm
31     if ($oldversion < 2008073000) {
32         $table = new xmldb_table('scorm');
33         $field = new xmldb_field('whatgrade');
34         $field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'grademethod');
36         /// Launch add field whatgrade
37         if (!$dbman->field_exists($table,$field)) {
38             $dbman->add_field($table, $field);
39             $whatgradefixed = get_config('scorm', 'whatgradefixed');
40             if (empty($whatgradefixed)) {
41                 /// fix bad usage of whatgrade/grading method.
42                 $scorms = $DB->get_records('scorm');
43                 if (!empty($scorm)) {
44                     foreach ($scorms as $scorm) {
45                         $scorm->whatgrade = $scorm->grademethod/10;
46                         $DB->update_record('scorm', $scorm);
47                     }
48                 }
49             }
50         } else {
51             //dump this config var as it isn't needed anymore.
52             unset_config('whatgradefixed', 'scorm');
53         }
55         upgrade_mod_savepoint(true, 2008073000, 'scorm');
56     }
58      if ($oldversion < 2008082500) {
60     /// Define field scormtype to be added to scorm
61         $table = new xmldb_table('scorm');
62         $field = new xmldb_field('scormtype', XMLDB_TYPE_CHAR, '50', null, XMLDB_NOTNULL, null, 'local', 'name');
64     /// Launch add field scormtype
65         $dbman->add_field($table, $field);
67     /// scorm savepoint reached
68         upgrade_mod_savepoint(true, 2008082500, 'scorm');
69     }
71     if ($oldversion < 2008090300) {
73     /// Define field sha1hash to be added to scorm
74         $table = new xmldb_table('scorm');
75         $field = new xmldb_field('sha1hash', XMLDB_TYPE_CHAR, '40', null, null, null, null, 'updatefreq');
77     /// Launch add field sha1hash
78         $dbman->add_field($table, $field);
80     /// scorm savepoint reached
81         upgrade_mod_savepoint(true, 2008090300, 'scorm');
82     }
84     if ($oldversion < 2008090301) {
86     /// Define field revision to be added to scorm
87         $table = new xmldb_table('scorm');
88         $field = new xmldb_field('revision', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'md5hash');
90     /// Launch add field revision
91         $dbman->add_field($table, $field);
93     /// scorm savepoint reached
94         upgrade_mod_savepoint(true, 2008090301, 'scorm');
95     }
97     if ($oldversion < 2008090302) {
98         $sql = "UPDATE {scorm}
99                    SET scormtype = 'external'
100                  WHERE reference LIKE ? OR reference LIKE ? OR reference LIKE ?";
101         $DB->execute($sql, array('http://%imsmanifest.xml', 'https://%imsmanifest.xml', 'www.%imsmanifest.xml'));
103         $sql = "UPDATE {scorm}
104                    SET scormtype = 'localsync'
105                  WHERE reference LIKE ? OR reference LIKE ? OR reference LIKE ?
106                        OR reference LIKE ? OR reference LIKE ? OR reference LIKE ?";
107         $DB->execute($sql, array('http://%.zip', 'https://%.zip', 'www.%.zip', 'http://%.pif', 'https://%.pif', 'www.%.pif'));
109         $sql = "UPDATE {scorm} SET scormtype = 'imsrepository' WHERE reference LIKE ?";
110         $DB->execute($sql, array('#%'));
112     /// scorm savepoint reached
113         upgrade_mod_savepoint(true, 2008090302, 'scorm');
114     }
116     if ($oldversion < 2008090303) {
117         //remove obsoleted config settings
118         unset_config('scorm_advancedsettings');
119         unset_config('scorm_windowsettings');
121     /// scorm savepoint reached
122         upgrade_mod_savepoint(true, 2008090303, 'scorm');
123     }
125     if ($oldversion < 2008090304) {
127         /////////////////////////////////////
128         /// new file storage upgrade code ///
129         /////////////////////////////////////
131         function scorm_migrate_content_files($context, $base, $path) {
132             global $CFG, $OUTPUT;
134             $fullpathname = $base.$path;
135             $fs           = get_file_storage();
136             $filearea     = 'content';
137             $items        = new DirectoryIterator($fullpathname);
139             foreach ($items as $item) {
140                 if ($item->isDot()) {
141                     unset($item); // release file handle
142                     continue;
143                 }
145                 if ($item->isLink()) {
146                     // do not follow symlinks - they were never supported in moddata, sorry
147                     unset($item); // release file handle
148                     continue;
149                 }
151                 if ($item->isFile()) {
152                     if (!$item->isReadable()) {
153                         echo $OUTPUT->notification(" File not readable, skipping: ".$fullpathname.$item->getFilename());
154                         unset($item); // release file handle
155                         continue;
156                     }
158                     $filepath    = clean_param($path, PARAM_PATH);
159                     $filename    = clean_param($item->getFilename(), PARAM_FILE);
160                     $oldpathname = $fullpathname.$item->getFilename();
162                     if ($filename === '') {
163                         continue;
164                         unset($item); // release file handle
165                     }
167                     if (!$fs->file_exists($context->id, 'mod_scorm', $filearea, '0', $filepath, $filename)) {
168                         $file_record = array('contextid'=>$context->id, 'component'=>'mod_scorm', 'filearea'=>$filearea, 'itemid'=>0, 'filepath'=>$filepath, 'filename'=>$filename,
169                                              'timecreated'=>$item->getCTime(), 'timemodified'=>$item->getMTime());
170                         unset($item); // release file handle
171                         if ($fs->create_file_from_pathname($file_record, $oldpathname)) {
172                             @unlink($oldpathname);
173                         }
174                     } else {
175                         unset($item); // release file handle
176                     }
178                 } else {
179                     //migrate recursively all subdirectories
180                     $oldpathname = $fullpathname.$item->getFilename().'/';
181                     $subpath     = $path.$item->getFilename().'/';
182                     unset($item);  // release file handle
183                     scorm_migrate_content_files($context, $base, $subpath);
184                     @rmdir($oldpathname); // deletes dir if empty
185                 }
186             }
187             unset($items); //release file handles
188         }
190         $fs = get_file_storage();
192         $sqlfrom = "FROM {scorm} s
193                     JOIN {modules} m ON m.name = 'scorm'
194                     JOIN {course_modules} cm ON (cm.module = m.id AND cm.instance = s.id)";
196         $count = $DB->count_records_sql("SELECT COUNT('x') $sqlfrom");
198         if ($rs = $DB->get_recordset_sql("SELECT s.id, s.scormtype, s.reference, s.course, cm.id AS cmid $sqlfrom ORDER BY s.course, s.id")) {
200             $pbar = new progress_bar('migratescormfiles', 500, true);
202             $i = 0;
203             foreach ($rs as $scorm) {
204                 $i++;
205                 upgrade_set_timeout(180); // set up timeout, may also abort execution
206                 $pbar->update($i, $count, "Migrating scorm files - $i/$count.");
208                 $context       = get_context_instance(CONTEXT_MODULE, $scorm->cmid);
209                 $coursecontext = get_context_instance(CONTEXT_COURSE, $scorm->course);
211                 // first copy local packages if found - do not delete in case they are shared ;-)
212                 if ($scorm->scormtype === 'local' and preg_match('/.*(\.zip|\.pif)$/i', $scorm->reference)) {
213                     $packagefile = clean_param($scorm->reference, PARAM_PATH);
214                     $pathnamehash = sha1("/$coursecontext->id/course/legacy/0/$packagefile");
215                     if ($file = $fs->get_file_by_hash($pathnamehash)) {
216                         $file_record = array('scontextid'=>$context->id, 'component'=>'mod_scorm', 'filearea'=>'package',
217                                              'itemid'=>0, 'filepath'=>'/');
218                         try {
219                             $fs->create_file_from_storedfile($file_record, $file);
220                         } catch (Exception $x) {
221                         }
222                         $scorm->reference = $file->get_filepath().$file->get_filename();
224                     } else {
225                         $scorm->reference = '';
226                     }
227                     $DB->update_record('scorm', $scorm);
228                 }
230                 // now migrate the extracted package
231                 $basepath = "$CFG->dataroot/$scorm->course/$CFG->moddata/scorm/$scorm->id";
232                 if (!is_dir($basepath)) {
233                     //no files?
234                     continue;
235                 }
237                 scorm_migrate_content_files($context, $basepath, '/');
239                 // remove dirs if empty
240                 @rmdir("$CFG->dataroot/$scorm->course/$CFG->moddata/scorm/$scorm->id/");
241                 @rmdir("$CFG->dataroot/$scorm->course/$CFG->moddata/scorm/");
242                 @rmdir("$CFG->dataroot/$scorm->course/$CFG->moddata/");
243             }
244             $rs->close();
245         }
247     /// scorm savepoint reached
248         upgrade_mod_savepoint(true, 2008090304, 'scorm');
249     }
252     if ($oldversion < 2008090305) {
254     /// Define new fields forcecompleted, forcenewattempt, displayattemptstatus, and displaycoursestructure to be added to scorm
255         $table = new xmldb_table('scorm');
256         $field = new xmldb_field('forcecompleted', XMLDB_TYPE_INTEGER, '1', null, null, null, '0', 'maxattempt');
257         if (!$dbman->field_exists($table,$field)) {
258             $dbman->add_field($table, $field);
259         }
260         $field = new xmldb_field('forcenewattempt', XMLDB_TYPE_INTEGER, '1', null, null, null, '0', 'forcecompleted');
261         if (!$dbman->field_exists($table,$field)) {
262             $dbman->add_field($table, $field);
263         }
264         $field = new xmldb_field('lastattemptlock', XMLDB_TYPE_INTEGER, '1', null, null, null, '0', 'forcenewattempt');
265         if (!$dbman->field_exists($table,$field)) {
266             $dbman->add_field($table, $field);
267         }
268         $field = new xmldb_field('displayattemptstatus', XMLDB_TYPE_INTEGER, '1', null, null, null, '1', 'lastattemptlock');
269         if (!$dbman->field_exists($table,$field)) {
270             $dbman->add_field($table, $field);
271         }
272         $field = new xmldb_field('displaycoursestructure', XMLDB_TYPE_INTEGER, '1', null, null, null, '1', 'displayattemptstatus');
273         if (!$dbman->field_exists($table,$field)) {
274             $dbman->add_field($table, $field);
275         }
277     /// scorm savepoint reached
278         upgrade_mod_savepoint(true, 2008090305, 'scorm');
279     }
282     // remove redundant config values
283     if ($oldversion < 2008090306) {
284         /*
285          * comment this out as it is handled by the update mark 2008090310 below
286          * left for historical documentation as some early adopters may have done
287          * this already.
288          $redundant_config = array(
289                          'scorm_allowapidebug',
290                          'scorm_allowtypeexternal',
291                          'scorm_allowtypeimsrepository',
292                          'scorm_allowtypelocalsync',
293                          'scorm_apidebugmask',
294                          'scorm_frameheight',
295                          'scorm_framewidth',
296                          'scorm_maxattempts',
297                          'scorm_updatetime');
298         foreach ($redundant_config as $rcfg) {
299             if (isset($CFG->$rcfg)) {
300                 unset_config($rcfg);
301             }
302         }
303          */
304         /// scorm savepoint reached
305         upgrade_mod_savepoint(true, 2008090306, 'scorm');
306     }
310     // remove redundant config values
311     if ($oldversion < 2008090307) {
312         /*
313          * comment this out as it is handled by the update mark 2008090310 below
314          * left for historical documentation as some early adopters may have done
315          * this already.
316          $redundant_config = array(
317                          'scorm_allowapidebug',
318                          'scorm_allowtypeexternal',
319                          'scorm_allowtypeimsrepository',
320                          'scorm_allowtypelocalsync',
321                          'scorm_apidebugmask',
322                          'scorm_frameheight',
323                          'scorm_framewidth',
324                          'scorm_maxattempts',
325                          'scorm_updatetime',
326                          'scorm_resizable',
327                          'scorm_scrollbars',
328                          'scorm_directories',
329                          'scorm_location',
330                          'scorm_menubar',
331                          'scorm_toolbar',
332                          'scorm_status',
333                          'scorm_grademethod',
334                          'scorm_maxgrade',
335                          'scorm_whatgrade',
336                          'scorm_popup',
337                          'scorm_skipview',
338                          'scorm_hidebrowse',
339                          'scorm_hidetoc',
340                          'scorm_hidenav',
341                          'scorm_auto',
342                          'scorm_updatefreq'
343          );
344         foreach ($redundant_config as $rcfg) {
345             if (isset($CFG->$rcfg)) {
346                 unset_config($rcfg);
347             }
348         }
349          */
351         /// scorm savepoint reached
352         upgrade_mod_savepoint(true, 2008090307, 'scorm');
353     }
355     if ($oldversion < 2008090308) {
356         $table = new xmldb_table('scorm');
357         $field = new xmldb_field('timeopen', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'height');
358         if (!$dbman->field_exists($table,$field)) {
359             $dbman->add_field($table, $field);
360         }
361         $field = new xmldb_field('timeclose', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'timeopen');
362         if (!$dbman->field_exists($table,$field)) {
363             $dbman->add_field($table, $field);
364         }
366         /// scorm savepoint reached
367         upgrade_mod_savepoint(true, 2008090308, 'scorm');
368     }
371     if ($oldversion < 2008090310) {
372         // take above blocks that delete config and move the values in to config_plugins
374         $redundant_config = array(
375                          'scorm_allowapidebug',
376                          'scorm_allowtypeexternal',
377                          'scorm_allowtypeimsrepository',
378                          'scorm_allowtypelocalsync',
379                          'scorm_apidebugmask',
380                          'scorm_frameheight',
381                          'scorm_framewidth',
382                          'scorm_maxattempts',
383                          'scorm_updatetime',
384                          'scorm_resizable',
385                          'scorm_scrollbars',
386                          'scorm_directories',
387                          'scorm_location',
388                          'scorm_menubar',
389                          'scorm_toolbar',
390                          'scorm_status',
391                          'scorm_grademethod',
392                          'scorm_maxgrade',
393                          'scorm_whatgrade',
394                          'scorm_popup',
395                          'scorm_skipview',
396                          'scorm_hidebrowse',
397                          'scorm_hidetoc',
398                          'scorm_hidenav',
399                          'scorm_auto',
400                          'scorm_updatefreq',
401                          'scorm_displayattemptstatus',
402                          'scorm_displaycoursestructure',
403                          'scorm_forcecompleted',
404                          'scorm_forcenewattempt',
405                          'scorm_lastattemptlock'
406          );
408         foreach ($redundant_config as $rcfg) {
409             if (isset($CFG->$rcfg)) {
410                 $shortname = substr($rcfg, 6);
411                 set_config($shortname, $CFG->$rcfg, 'scorm');
412                 unset_config($rcfg);
413             }
414         }
416         /// scorm savepoint reached
417         upgrade_mod_savepoint(true, 2008090310, 'scorm');
418     }
420     if ($oldversion < 2009042000) {
422     /// Rename field summary on table scorm to intro
423         $table = new xmldb_table('scorm');
424         $field = new xmldb_field('summary', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL, null, null, 'reference');
426     /// Launch rename field summary
427         $dbman->rename_field($table, $field, 'intro');
429     /// scorm savepoint reached
430         upgrade_mod_savepoint(true, 2009042000, 'scorm');
431     }
433     if ($oldversion < 2009042001) {
435     /// Define field introformat to be added to scorm
436         $table = new xmldb_table('scorm');
437         $field = new xmldb_field('introformat', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'intro');
439     /// Launch add field introformat
440         if (!$dbman->field_exists($table, $field)) {
441             $dbman->add_field($table, $field);
442         }
444         // conditionally migrate to html format in intro
445         if ($CFG->texteditors !== 'textarea') {
446             $rs = $DB->get_recordset('scorm', array('introformat'=>FORMAT_MOODLE), '', 'id,intro,introformat');
447             foreach ($rs as $s) {
448                 $s->intro       = text_to_html($s->intro, false, false, true);
449                 $s->introformat = FORMAT_HTML;
450                 $DB->update_record('scorm', $s);
451                 upgrade_set_timeout();
452             }
453             $rs->close();
454         }
456     /// scorm savepoint reached
457         upgrade_mod_savepoint(true, 2009042001, 'scorm');
458     }
460     if ($oldversion < 2009042002) {
462     /// Define field introformat to be added to scorm
463         $table = new xmldb_table('scorm_scoes');
464         $field = new xmldb_field('launch', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL, null, null);
466     /// Launch add field introformat
467         $dbman->change_field_type($table, $field);
469     /// scorm savepoint reached
470         upgrade_mod_savepoint(true, 2009042002, 'scorm');
471     }
472     if ($oldversion < 2010070800) {
473     //check to see if this has already been tidied up by a 1.9 upgrade.
474         $grademethodfixed = get_config('scorm', 'grademethodfixed');
475         if (empty($grademethodfixed)) {
476             /// fix bad usage of whatgrade/grading method.
477             $scorms = $DB->get_records('scorm');
478             if (!empty($scorm)) {
479                 foreach ($scorms as $scorm) {
480                     $scorm->grademethod = $scorm->grademethod%10;
481                     $DB->update_record('scorm', $scorm);
482                 }
483             }
484         } else {
485             //dump this config var as it isn't needed anymore.
486             unset_config('grademethodfixed', 'scorm');
487         }
489     /// scorm savepoint reached
490         upgrade_mod_savepoint(true, 2010070800, 'scorm');
491     }
492     return true;