e68ec413a6cc0b36fdcdbf784e01e3150f328cd7
[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 /**
24  * @global moodle_database $DB
25  * @param int $oldversion
26  * @return bool
27  */
28 function xmldb_scorm_upgrade($oldversion) {
29     global $CFG, $DB;
31     $dbman = $DB->get_manager();
33 //===== 1.9.0 upgrade line ======//
35     // Adding missing 'whatgrade' field to table scorm
36     if ($oldversion < 2008073000) {
37         $table = new xmldb_table('scorm');
38         $field = new xmldb_field('whatgrade');
39         $field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'grademethod');
41         /// Launch add field whatgrade
42         if (!$dbman->field_exists($table,$field)) {
43             $dbman->add_field($table, $field);
44             $whatgradefixed = get_config('scorm', 'whatgradefixed');
45             if (empty($whatgradefixed)) {
46                 /// fix bad usage of whatgrade/grading method.
47                 $scorms = $DB->get_records('scorm');
48                 foreach ($scorms as $scorm) {
49                     $scorm->whatgrade = $scorm->grademethod/10;
50                     $DB->update_record('scorm', $scorm);
51                 }
52             }
53         } else {
54             //dump this config var as it isn't needed anymore.
55             unset_config('whatgradefixed', 'scorm');
56         }
58         upgrade_mod_savepoint(true, 2008073000, 'scorm');
59     }
61      if ($oldversion < 2008082500) {
63     /// Define field scormtype to be added to scorm
64         $table = new xmldb_table('scorm');
65         $field = new xmldb_field('scormtype', XMLDB_TYPE_CHAR, '50', null, XMLDB_NOTNULL, null, 'local', 'name');
67     /// Launch add field scormtype
68         $dbman->add_field($table, $field);
70     /// scorm savepoint reached
71         upgrade_mod_savepoint(true, 2008082500, 'scorm');
72     }
74     if ($oldversion < 2008090300) {
76     /// Define field sha1hash to be added to scorm
77         $table = new xmldb_table('scorm');
78         $field = new xmldb_field('sha1hash', XMLDB_TYPE_CHAR, '40', null, null, null, null, 'updatefreq');
80     /// Launch add field sha1hash
81         $dbman->add_field($table, $field);
83     /// scorm savepoint reached
84         upgrade_mod_savepoint(true, 2008090300, 'scorm');
85     }
87     if ($oldversion < 2008090301) {
89     /// Define field revision to be added to scorm
90         $table = new xmldb_table('scorm');
91         $field = new xmldb_field('revision', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'md5hash');
93     /// Launch add field revision
94         $dbman->add_field($table, $field);
96     /// scorm savepoint reached
97         upgrade_mod_savepoint(true, 2008090301, 'scorm');
98     }
100     if ($oldversion < 2008090302) {
101         $sql = "UPDATE {scorm}
102                    SET scormtype = 'external'
103                  WHERE reference LIKE ? OR reference LIKE ? OR reference LIKE ?";
104         $DB->execute($sql, array('http://%imsmanifest.xml', 'https://%imsmanifest.xml', 'www.%imsmanifest.xml'));
106         $sql = "UPDATE {scorm}
107                    SET scormtype = 'localsync'
108                  WHERE reference LIKE ? OR reference LIKE ? OR reference LIKE ?
109                        OR reference LIKE ? OR reference LIKE ? OR reference LIKE ?";
110         $DB->execute($sql, array('http://%.zip', 'https://%.zip', 'www.%.zip', 'http://%.pif', 'https://%.pif', 'www.%.pif'));
112         $sql = "UPDATE {scorm} SET scormtype = 'imsrepository' WHERE reference LIKE ?";
113         $DB->execute($sql, array('#%'));
115     /// scorm savepoint reached
116         upgrade_mod_savepoint(true, 2008090302, 'scorm');
117     }
119     if ($oldversion < 2008090303) {
120         //remove obsoleted config settings
121         unset_config('scorm_advancedsettings');
122         unset_config('scorm_windowsettings');
124     /// scorm savepoint reached
125         upgrade_mod_savepoint(true, 2008090303, 'scorm');
126     }
128     if ($oldversion < 2008090304) {
129         /////////////////////////////////////
130         /// new file storage upgrade code ///
131         /////////////////////////////////////
133         require_once("$CFG->dirroot/mod/scorm/db/upgradelib.php");
135         $fs = get_file_storage();
137         $sqlfrom = "FROM {scorm} s
138                     JOIN {modules} m ON m.name = 'scorm'
139                     JOIN {course_modules} cm ON (cm.module = m.id AND cm.instance = s.id)";
141         $count = $DB->count_records_sql("SELECT COUNT('x') $sqlfrom");
143         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")) {
145             $pbar = new progress_bar('migratescormfiles', 500, true);
147             $i = 0;
148             foreach ($rs as $scorm) {
149                 $i++;
150                 upgrade_set_timeout(180); // set up timeout, may also abort execution
151                 $pbar->update($i, $count, "Migrating scorm files - $i/$count.");
153                 $context       = get_context_instance(CONTEXT_MODULE, $scorm->cmid);
154                 $coursecontext = get_context_instance(CONTEXT_COURSE, $scorm->course);
156                 if ($scorm->scormtype === 'local' and preg_match('/.*(\.zip|\.pif)$/i', $scorm->reference)) {
157                     // first copy local packages if found - do not delete in case they are shared ;-)
158                     $packagefile = clean_param($scorm->reference, PARAM_PATH);
159                     $pathnamehash = sha1("/$coursecontext->id/course/legacy/0/$packagefile");
160                     if ($file = $fs->get_file_by_hash($pathnamehash)) {
161                         $file_record = array('contextid'=>$context->id, 'component'=>'mod_scorm', 'filearea'=>'package',
162                                              'itemid'=>0, 'filepath'=>'/');
163                         try {
164                             $fs->create_file_from_storedfile($file_record, $file);
165                         } catch (Exception $x) {
166                             // ignore any errors, we can not do much anyway
167                         }
168                         $scorm->reference = $file->get_filepath().$file->get_filename();
170                     } else {
171                         $scorm->reference = '';
172                     }
173                     $DB->update_record('scorm', $scorm);
174                     // the package should be already extracted, we need to move the files there
175                     // just in case somebody modified it directly there
176                     scorm_migrate_moddata_files($scorm, $context);
178                 } else if ($scorm->scormtype === 'local' and preg_match('/.*\/imsmanifest\.xml$/i', $scorm->reference)) {
179                     // ignore imsmanifest in course root because we would be duplicating all course files which is not acceptable
180                     // moddata dir is not used at all, ignore any rubbish there
181                     $manifest = clean_param($scorm->reference, PARAM_PATH);
183                     $pathnamehash = sha1("/$coursecontext->id/course/legacy/0/$manifest");
184                     if ($file = $fs->get_file_by_hash($pathnamehash)) {
185                         $scorm->reference = $file->get_filepath().$file->get_filename();
187                         $manifestdir = '/'.str_ireplace('/imsmanifest.xml', '', $manifest).'/';
188                         $pregmanifestdir = preg_quote($manifestdir, '/');
189                         $file_record = array('contextid'=>$context->id, 'component'=>'mod_scorm', 'filearea'=>'content', 'itemid'=>0);
190                         if ($files = $fs->get_directory_files($coursecontext->id, 'course', 'legacy', 0, $manifestdir, true)) {
191                             foreach ($files as $file) {
192                                 $file_record['filepath'] = preg_replace("/^$pregmanifestdir/", '/', $file->get_filepath());
193                                 try {
194                                     $fs->create_file_from_storedfile($file_record, $file);
195                                 } catch (Exception $x) {
196                                     // ignore any errors, we can not do much anyway
197                                 }
198                             }
199                         }
201                     } else {
202                         $scorm->reference = '';
203                     }
204                     $DB->update_record('scorm', $scorm);
206                 } else {
207                     // just try to migrate anything from moddata
208                     scorm_migrate_moddata_files($scorm, $context);
209                 }
211                 // remove dirs if empty
212                 @rmdir("$CFG->dataroot/$scorm->course/$CFG->moddata/scorm/$scorm->id/");
213                 @rmdir("$CFG->dataroot/$scorm->course/$CFG->moddata/scorm/");
214                 @rmdir("$CFG->dataroot/$scorm->course/$CFG->moddata/");
215             }
216             $rs->close();
217         }
219     /// scorm savepoint reached
220         upgrade_mod_savepoint(true, 2008090304, 'scorm');
221     }
224     if ($oldversion < 2008090305) {
226     /// Define new fields forcecompleted, forcenewattempt, displayattemptstatus, and displaycoursestructure to be added to scorm
227         $table = new xmldb_table('scorm');
228         $field = new xmldb_field('forcecompleted', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, 1, 'maxattempt');
229         if (!$dbman->field_exists($table,$field)) {
230             $dbman->add_field($table, $field);
231         }
232         $field = new xmldb_field('forcenewattempt', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, 0, 'forcecompleted');
233         if (!$dbman->field_exists($table,$field)) {
234             $dbman->add_field($table, $field);
235         }
236         $field = new xmldb_field('lastattemptlock', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, 0, 'forcenewattempt');
237         if (!$dbman->field_exists($table,$field)) {
238             $dbman->add_field($table, $field);
239         }
240         $field = new xmldb_field('displayattemptstatus', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, 1, 'lastattemptlock');
241         if (!$dbman->field_exists($table,$field)) {
242             $dbman->add_field($table, $field);
243         }
244         $field = new xmldb_field('displaycoursestructure', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, 1, 'displayattemptstatus');
245         if (!$dbman->field_exists($table,$field)) {
246             $dbman->add_field($table, $field);
247         }
249     /// scorm savepoint reached
250         upgrade_mod_savepoint(true, 2008090305, 'scorm');
251     }
254     // remove redundant config values
255     if ($oldversion < 2008090306) {
256         /*
257          * comment this out as it is handled by the update mark 2008090310 below
258          * left for historical documentation as some early adopters may have done
259          * this already.
260          $redundant_config = array(
261                          'scorm_allowapidebug',
262                          'scorm_allowtypeexternal',
263                          'scorm_allowtypeimsrepository',
264                          'scorm_allowtypelocalsync',
265                          'scorm_apidebugmask',
266                          'scorm_frameheight',
267                          'scorm_framewidth',
268                          'scorm_maxattempts',
269                          'scorm_updatetime');
270         foreach ($redundant_config as $rcfg) {
271             if (isset($CFG->$rcfg)) {
272                 unset_config($rcfg);
273             }
274         }
275          */
276         /// scorm savepoint reached
277         upgrade_mod_savepoint(true, 2008090306, 'scorm');
278     }
282     // remove redundant config values
283     if ($oldversion < 2008090307) {
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                          'scorm_resizable',
299                          'scorm_scrollbars',
300                          'scorm_directories',
301                          'scorm_location',
302                          'scorm_menubar',
303                          'scorm_toolbar',
304                          'scorm_status',
305                          'scorm_grademethod',
306                          'scorm_maxgrade',
307                          'scorm_whatgrade',
308                          'scorm_popup',
309                          'scorm_skipview',
310                          'scorm_hidebrowse',
311                          'scorm_hidetoc',
312                          'scorm_hidenav',
313                          'scorm_auto',
314                          'scorm_updatefreq'
315          );
316         foreach ($redundant_config as $rcfg) {
317             if (isset($CFG->$rcfg)) {
318                 unset_config($rcfg);
319             }
320         }
321          */
323         /// scorm savepoint reached
324         upgrade_mod_savepoint(true, 2008090307, 'scorm');
325     }
327     if ($oldversion < 2008090308) {
328         $table = new xmldb_table('scorm');
329         $field = new xmldb_field('timeopen', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'height');
330         if (!$dbman->field_exists($table,$field)) {
331             $dbman->add_field($table, $field);
332         }
333         $field = new xmldb_field('timeclose', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'timeopen');
334         if (!$dbman->field_exists($table,$field)) {
335             $dbman->add_field($table, $field);
336         }
338         /// scorm savepoint reached
339         upgrade_mod_savepoint(true, 2008090308, 'scorm');
340     }
343     if ($oldversion < 2008090310) {
344         // take above blocks that delete config and move the values in to config_plugins
346         $redundant_config = array(
347                          'scorm_allowapidebug',
348                          'scorm_allowtypeexternal',
349                          'scorm_allowtypeimsrepository',
350                          'scorm_allowtypelocalsync',
351                          'scorm_apidebugmask',
352                          'scorm_frameheight',
353                          'scorm_framewidth',
354                          'scorm_maxattempts',
355                          'scorm_updatetime',
356                          'scorm_resizable',
357                          'scorm_scrollbars',
358                          'scorm_directories',
359                          'scorm_location',
360                          'scorm_menubar',
361                          'scorm_toolbar',
362                          'scorm_status',
363                          'scorm_grademethod',
364                          'scorm_maxgrade',
365                          'scorm_whatgrade',
366                          'scorm_popup',
367                          'scorm_skipview',
368                          'scorm_hidebrowse',
369                          'scorm_hidetoc',
370                          'scorm_hidenav',
371                          'scorm_auto',
372                          'scorm_updatefreq',
373                          'scorm_displayattemptstatus',
374                          'scorm_displaycoursestructure',
375                          'scorm_forcecompleted',
376                          'scorm_forcenewattempt',
377                          'scorm_lastattemptlock'
378          );
380         foreach ($redundant_config as $rcfg) {
381             if (isset($CFG->$rcfg)) {
382                 $shortname = substr($rcfg, 6);
383                 set_config($shortname, $CFG->$rcfg, 'scorm');
384                 unset_config($rcfg);
385             }
386         }
388         /// scorm savepoint reached
389         upgrade_mod_savepoint(true, 2008090310, 'scorm');
390     }
392     if ($oldversion < 2009042000) {
394     /// Rename field summary on table scorm to intro
395         $table = new xmldb_table('scorm');
396         $field = new xmldb_field('summary', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL, null, null, 'reference');
398     /// Launch rename field summary
399         $dbman->rename_field($table, $field, 'intro');
401     /// scorm savepoint reached
402         upgrade_mod_savepoint(true, 2009042000, 'scorm');
403     }
405     if ($oldversion < 2009042001) {
407     /// Define field introformat to be added to scorm
408         $table = new xmldb_table('scorm');
409         $field = new xmldb_field('introformat', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'intro');
411     /// Launch add field introformat
412         if (!$dbman->field_exists($table, $field)) {
413             $dbman->add_field($table, $field);
414         }
416         // conditionally migrate to html format in intro
417         if ($CFG->texteditors !== 'textarea') {
418             $rs = $DB->get_recordset('scorm', array('introformat'=>FORMAT_MOODLE), '', 'id,intro,introformat');
419             foreach ($rs as $s) {
420                 $s->intro       = text_to_html($s->intro, false, false, true);
421                 $s->introformat = FORMAT_HTML;
422                 $DB->update_record('scorm', $s);
423                 upgrade_set_timeout();
424             }
425             $rs->close();
426         }
428     /// scorm savepoint reached
429         upgrade_mod_savepoint(true, 2009042001, 'scorm');
430     }
432     if ($oldversion < 2009042002) {
434     /// Define field introformat to be added to scorm
435         $table = new xmldb_table('scorm_scoes');
436         $field = new xmldb_field('launch', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL, null, null);
438     /// Launch add field introformat
439         $dbman->change_field_type($table, $field);
441     /// scorm savepoint reached
442         upgrade_mod_savepoint(true, 2009042002, 'scorm');
443     }
444     if ($oldversion < 2010070800) {
445     //check to see if this has already been tidied up by a 1.9 upgrade.
446         $grademethodfixed = get_config('scorm', 'grademethodfixed');
447         if (empty($grademethodfixed)) {
448             /// fix bad usage of whatgrade/grading method.
449             $scorms = $DB->get_records('scorm');
450             if (!empty($scorm)) {
451                 foreach ($scorms as $scorm) {
452                     $scorm->grademethod = $scorm->grademethod%10;
453                     $DB->update_record('scorm', $scorm);
454                 }
455             }
456         } else {
457             //dump this config var as it isn't needed anymore.
458             unset_config('grademethodfixed', 'scorm');
459         }
461     /// scorm savepoint reached
462         upgrade_mod_savepoint(true, 2010070800, 'scorm');
463     }
464     if ($oldversion < 2010092400) {
465         $count = $DB->count_records('scorm', array('scormtype'=>'external'));
466         if (!empty($count)) {
467             set_config('allowtypeexternal', '1', 'scorm');
468         }
469         $count = $DB->count_records('scorm', array('scormtype'=>'localsync'));
470         if (!empty($count)) {
471             set_config('allowtypelocalsync', '1', 'scorm');
472         }
473         $count = $DB->count_records('scorm', array('scormtype'=>'imsrepository'));
474         if (!empty($count)) {
475             set_config('allowtypeimsrepository', '1', 'scorm');
476         }
477         /// scorm savepoint reached
478         upgrade_mod_savepoint(true, 2010092400, 'scorm');
479     }
480     
481     if ($oldversion < 2010122300) {
482         // Fix scorm in the post table after upgrade from 1.9
483         $table = new xmldb_table('scorm');
484         $columns = $DB->get_columns('scorm');
486         if (array_key_exists('forcecompleted', $columns) && empty($columns['forcecompleted']->not_null)) {
487             // forcecompleted should be bigint(10) NOT NULL DEFAULT '1'
488             // Fixed in earlier upgrade code
489             $field = new xmldb_field('forcecompleted', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, 1, 'maxattempt');
490             if ($dbman->field_exists($table, $field)) {
491                 $dbman->change_field_precision($table, $field);
492             }
493         }
495         if (array_key_exists('forcenewattempt', $columns) && empty($columns['forcenewattempt']->not_null)) {
496             // forcenewattempt should be NOT NULL
497             // Fixed in earlier upgrade code
498             $field = new xmldb_field('forcenewattempt', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, 0, 'forcecompleted');
499             if ($dbman->field_exists($table, $field)) {
500                 $dbman->change_field_notnull($table, $field);
501             }
502         }
504         if (array_key_exists('lastattemptlock', $columns) && empty($columns['lastattemptlock']->not_null)) {
505             // lastattemptlock should be NOT NULL
506             // Fixed in earlier upgrade code
507             $field = new xmldb_field('lastattemptlock', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, 0, 'forcenewattempt');
508             if ($dbman->field_exists($table, $field)) {
509                 $dbman->change_field_notnull($table, $field);
510             }
511         }
513         if (array_key_exists('displayattemptstatus', $columns) && empty($columns['displayattemptstatus']->not_null)) {
514             // displayattemptstatus should be NOT NULL
515             // Fixed in earlier upgrade code
516             $field = new xmldb_field('displayattemptstatus', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, 1, 'lastattemptlock');
517             if ($dbman->field_exists($table, $field)) {
518                 $dbman->change_field_notnull($table, $field);
519             }
520         }
522         if (array_key_exists('displaycoursestructure', $columns) && empty($columns['displaycoursestructure']->not_null)) {
523             // displaycoursestructure should be NOT NULL
524             // Fixed in earlier upgrade code
525             $field = new xmldb_field('displaycoursestructure', XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, 1, 'displayattemptstatus');
526             if ($dbman->field_exists($table, $field)) {
527                 $dbman->change_field_notnull($table, $field);
528             }
529         }
531         upgrade_mod_savepoint(true, 2010122300, 'scorm');
532     }
533     
534     return true;