lib MDL-19236 Added boilerplates and copyrights
[moodle.git] / lib / upgradelib.php
CommitLineData
96db14f9 1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
db9d4a3d 17
18/**
96db14f9 19 * Various upgrade related functions an classes.
db9d4a3d 20 *
96db14f9 21 * @package moodlecore
22 * @subpackage upgrade
23 * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
db9d4a3d 25 */
26
27define('UPGRADE_LOG_NORMAL', 0);
28define('UPGRADE_LOG_NOTICE', 1);
795a08ad 29define('UPGRADE_LOG_ERROR', 2);
30
31/**
32 * Exception indicating unknown error during upgrade.
33 */
34class upgrade_exception extends moodle_exception {
35 function __construct($plugin, $version) {
36 global $CFG;
37 $a = (object)array('plugin'=>$plugin, 'version'=>$version);
38 parent::__construct('upgradeerror', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $a);
39 }
40}
41
42/**
43 * Exception indicating downgrade error during upgrade.
44 */
45class downgrade_exception extends moodle_exception {
46 function __construct($plugin, $oldversion, $newversion) {
47 global $CFG;
48 $plugin = is_null($plugin) ? 'moodle' : $plugin;
49 $a = (object)array('plugin'=>$plugin, 'oldversion'=>$oldversion, 'newversion'=>$newversion);
50 parent::__construct('cannotdowngrade', 'debug', "$CFG->wwwroot/$CFG->admin/index.php", $a);
51 }
52}
53
54class upgrade_requires_exception extends moodle_exception {
55 function __construct($plugin, $pluginversion, $currentmoodle, $requiremoodle) {
56 global $CFG;
57 $a = new object();
58 $a->pluginname = $plugin;
59 $a->pluginversion = $pluginversion;
60 $a->currentmoodle = $currentmoodle;
61 $a->requiremoodle = $currentmoodle;
62 parent::__construct('pluginrequirementsnotmet', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $a);
63 }
64}
65
66class plugin_defective_exception extends moodle_exception {
67 function __construct($plugin, $details) {
68 global $CFG;
69 parent::__construct('detectedbrokenplugin', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $plugin, $details);
70 }
71}
db9d4a3d 72
73/**
74 * Insert or update log display entry. Entry may already exist.
75 * $module, $action must be unique
76 *
77 * @param string $module
78 * @param string $action
79 * @param string $mtable
80 * @param string $field
81 * @return void
82 *
83 */
84function update_log_display_entry($module, $action, $mtable, $field) {
85 global $DB;
86
87 if ($type = $DB->get_record('log_display', array('module'=>$module, 'action'=>$action))) {
88 $type->mtable = $mtable;
89 $type->field = $field;
90 $DB->update_record('log_display', $type);
91
92 } else {
93 $type = new object();
94 $type->module = $module;
95 $type->action = $action;
96 $type->mtable = $mtable;
97 $type->field = $field;
98
99 $DB->insert_record('log_display', $type, false);
100 }
101}
102
103/**
104 * Upgrade savepoint, marks end of each upgrade block.
105 * It stores new main version, resets upgrade timeout
106 * and abort upgrade if user cancels page loading.
107 *
108 * Please do not make large upgrade blocks with lots of operations,
109 * for example when adding tables keep only one table operation per block.
110 *
111 * @param bool $result false if upgrade step failed, true if completed
112 * @param string or float $version main version
113 * @param bool $allowabort allow user to abort script execution here
114 * @return void
115 */
116function upgrade_main_savepoint($result, $version, $allowabort=true) {
117 global $CFG;
118
795a08ad 119 if (!$result) {
120 throw new upgrade_exception('moodle core', $version);
121 }
122
123 if ($CFG->version >= $version) {
124 // something really wrong is going on in main upgrade script
125 throw new downgrade_exception(null, $CFG->version, $version);
db9d4a3d 126 }
127
795a08ad 128 set_config('version', $version);
129 upgrade_log(UPGRADE_LOG_NORMAL, null, 'Upgrade savepoint reached');
130
db9d4a3d 131 // reset upgrade timeout to default
132 upgrade_set_timeout();
133
134 // this is a safe place to stop upgrades if user aborts page loading
135 if ($allowabort and connection_aborted()) {
136 die;
137 }
138}
139
140/**
141 * Module upgrade savepoint, marks end of module upgrade blocks
142 * It stores module version, resets upgrade timeout
143 * and abort upgrade if user cancels page loading.
144 *
145 * @param bool $result false if upgrade step failed, true if completed
146 * @param string or float $version main version
147 * @param string $modname name of module
148 * @param bool $allowabort allow user to abort script execution here
149 * @return void
150 */
151function upgrade_mod_savepoint($result, $version, $modname, $allowabort=true) {
152 global $DB;
153
795a08ad 154 if (!$result) {
155 throw new upgrade_exception("mod/$modname", $version);
156 }
157
db9d4a3d 158 if (!$module = $DB->get_record('modules', array('name'=>$modname))) {
159 print_error('modulenotexist', 'debug', '', $modname);
160 }
161
795a08ad 162 if ($module->version >= $version) {
163 // something really wrong is going on in upgrade script
164 throw new downgrade_exception("mod/$modname", $module->version, $version);
db9d4a3d 165 }
795a08ad 166 $module->version = $version;
167 $DB->update_record('modules', $module);
168 upgrade_log(UPGRADE_LOG_NORMAL, "mod/$modname", 'Upgrade savepoint reached');
db9d4a3d 169
170 // reset upgrade timeout to default
171 upgrade_set_timeout();
172
173 // this is a safe place to stop upgrades if user aborts page loading
174 if ($allowabort and connection_aborted()) {
175 die;
176 }
177}
178
179/**
180 * Blocks upgrade savepoint, marks end of blocks upgrade blocks
181 * It stores block version, resets upgrade timeout
182 * and abort upgrade if user cancels page loading.
183 *
184 * @param bool $result false if upgrade step failed, true if completed
185 * @param string or float $version main version
186 * @param string $blockname name of block
187 * @param bool $allowabort allow user to abort script execution here
188 * @return void
189 */
795a08ad 190function upgrade_block_savepoint($result, $version, $blockname, $allowabort=true) {
db9d4a3d 191 global $DB;
192
795a08ad 193 if (!$result) {
194 throw new upgrade_exception("blocks/$blockname", $version);
195 }
196
db9d4a3d 197 if (!$block = $DB->get_record('block', array('name'=>$blockname))) {
198 print_error('blocknotexist', 'debug', '', $blockname);
199 }
200
795a08ad 201 if ($block->version >= $version) {
202 // something really wrong is going on in upgrade script
203 throw new downgrade_exception("blocks/$blockname", $block->version, $version);
db9d4a3d 204 }
795a08ad 205 $block->version = $version;
206 $DB->update_record('block', $block);
207 upgrade_log(UPGRADE_LOG_NORMAL, "blocks/$blockname", 'Upgrade savepoint reached');
db9d4a3d 208
209 // reset upgrade timeout to default
210 upgrade_set_timeout();
211
212 // this is a safe place to stop upgrades if user aborts page loading
213 if ($allowabort and connection_aborted()) {
214 die;
215 }
216}
217
218/**
219 * Plugins upgrade savepoint, marks end of blocks upgrade blocks
220 * It stores plugin version, resets upgrade timeout
221 * and abort upgrade if user cancels page loading.
222 *
223 * @param bool $result false if upgrade step failed, true if completed
224 * @param string or float $version main version
225 * @param string $type name of plugin
226 * @param string $dir location of plugin
227 * @param bool $allowabort allow user to abort script execution here
228 * @return void
229 */
230function upgrade_plugin_savepoint($result, $version, $type, $dir, $allowabort=true) {
795a08ad 231 if (!$result) {
232 throw new upgrade_exception("$type/$dir", $version);
db9d4a3d 233 }
234
795a08ad 235 $fullname = $type.'_'.$dir;
236 $component = $type.'/'.$dir;
237
238 $installedversion = get_config($fullname, 'version');
239 if ($installedversion >= $version) {
240 // Something really wrong is going on in the upgrade script
241 throw new downgrade_exception($component, $installedversion, $version);
242 }
243 set_config('version', $version, $fullname);
244 upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached');
245
db9d4a3d 246 // Reset upgrade timeout to default
247 upgrade_set_timeout();
248
249 // This is a safe place to stop upgrades if user aborts page loading
250 if ($allowabort and connection_aborted()) {
251 die;
252 }
253}
254
255
256/**
257 * Upgrade plugins
258 *
259 * @uses $CFG
260 * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
261 * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes')
262 * @param string $return The url to prompt the user to continue to
263 */
795a08ad 264function upgrade_plugins($type, $dir, $startcallback, $endcallback) {
db9d4a3d 265 global $CFG, $DB;
266
267/// special cases
268 if ($type === 'mod') {
795a08ad 269 return upgrade_plugins_modules($startcallback, $endcallback);
270 } else if ($type === 'block') {
271 return upgrade_plugins_blocks($startcallback, $endcallback);
db9d4a3d 272 }
273
274 $plugs = get_list_of_plugins($dir);
db9d4a3d 275
276 foreach ($plugs as $plug) {
277
795a08ad 278 $fullplug = $CFG->dirroot.'/'.$dir.'/'.$plug;
279 $component = $type.'/'.$plug; // standardised plugin name
db9d4a3d 280
795a08ad 281 if (!is_readable($fullplug.'/version.php')) {
282 continue;
db9d4a3d 283 }
284
795a08ad 285 $plugin = new object();
286 require($fullplug.'/version.php'); // defines $plugin with version etc
db9d4a3d 287
795a08ad 288 if (empty($plugin->version)) {
289 throw new plugin_defective_exception($component, 'Missing version value in version.php');
db9d4a3d 290 }
291
795a08ad 292 $plugin->name = $plug; // The name MUST match the directory
293 $plugin->fullname = $type.'_'.$plug; // The name MUST match the directory
294
295
db9d4a3d 296 if (!empty($plugin->requires)) {
297 if ($plugin->requires > $CFG->version) {
795a08ad 298 throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires);
db9d4a3d 299 }
300 }
301
db9d4a3d 302 $installedversion = get_config($plugin->fullname, 'version');
303
795a08ad 304 if (empty($installedversion)) { // new installation
305 $startcallback($component, true);
db9d4a3d 306
795a08ad 307 /// Install tables if defined
308 if (file_exists($fullplug.'/db/install.xml')) {
309 $DB->get_manager()->install_from_xmldb_file($fullplug.'/db/install.xml');
db9d4a3d 310 }
795a08ad 311 /// execute post install file
312 if (file_exists($fullplug.'/db/install.php')) {
313 require_once($fullplug.'/db/install.php');
314 $post_install_function = 'xmldb_'.$plugin->fullname.'_install';;
315 $post_install_function();
316 }
317
318 /// store version
319 upgrade_plugin_savepoint(true, $plugin->version, $type, $plug, false);
320
321 /// Install various components
322 update_capabilities($component);
323 events_update_definition($component);
324 message_update_providers($component);
325
326 $endcallback($component, true);
327
328 } else if ($installedversion < $plugin->version) { // upgrade
329 /// Run the upgrade function for the plugin.
330 $startcallback($component, false);
331
332 if (is_readable($fullplug.'/db/upgrade.php')) {
333 require_once($fullplug.'/db/upgrade.php'); // defines upgrading function
334
335 $newupgrade_function = 'xmldb_'.$plugin->fullname.'_upgrade';
336 $result = $newupgrade_function($installedversion);
337 } else {
338 $result = true;
339 }
340
341 $installedversion = get_config($plugin->fullname, 'version');
342 if ($installedversion < $plugin->version) {
343 // store version if not already there
344 upgrade_plugin_savepoint($result, $plugin->version, $type, $plug, false);
345 }
346
347 /// Upgrade various components
348 update_capabilities($component);
349 events_update_definition($component);
350 message_update_providers($component);
351
352 $endcallback($component, false);
353
354 } else if ($installedversion > $plugin->version) {
355 throw new downgrade_exception($component, $installedversion, $plugin->version);
db9d4a3d 356 }
357 }
db9d4a3d 358}
359
360/**
361 * Find and check all modules and load them up or upgrade them if necessary
362 */
795a08ad 363function upgrade_plugins_modules($startcallback, $endcallback) {
db9d4a3d 364 global $CFG, $DB;
365
795a08ad 366 $mods = get_list_of_plugins('mod');
db9d4a3d 367
368 foreach ($mods as $mod) {
369
370 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
371 continue;
372 }
373
795a08ad 374 $fullmod = $CFG->dirroot.'/mod/'.$mod;
375 $component = 'mod/'.$mod;
db9d4a3d 376
795a08ad 377 if (!is_readable($fullmod.'/version.php')) {
378 throw new plugin_defective_exception($component, 'Missing version.php');
db9d4a3d 379 }
380
795a08ad 381 $module = new object();
382 require($fullmod .'/version.php'); // defines $module with version etc
db9d4a3d 383
795a08ad 384 if (empty($module->version)) {
c1fe2368 385 if (isset($module->version)) {
386 // Version is empty but is set - it means its value is 0 or ''. Let us skip such module.
387 // This is inteded for developers so they can work on the early stages of the module.
388 continue;
389 }
795a08ad 390 throw new plugin_defective_exception($component, 'Missing version value in version.php');
db9d4a3d 391 }
392
393 if (!empty($module->requires)) {
394 if ($module->requires > $CFG->version) {
795a08ad 395 throw new upgrade_requires_exception($component, $module->version, $CFG->version, $module->requires);
db9d4a3d 396 }
397 }
398
399 $module->name = $mod; // The name MUST match the directory
400
795a08ad 401 $currmodule = $DB->get_record('modules', array('name'=>$module->name));
db9d4a3d 402
795a08ad 403 if (empty($currmodule->version)) {
404 $startcallback($component, true);
db9d4a3d 405
795a08ad 406 /// Execute install.xml (XMLDB) - must be present in all modules
407 $DB->get_manager()->install_from_xmldb_file($fullmod.'/db/install.xml');
db9d4a3d 408
409 /// Post installation hook - optional
410 if (file_exists("$fullmod/db/install.php")) {
411 require_once("$fullmod/db/install.php");
412 $post_install_function = 'xmldb_'.$module->name.'_install';;
413 $post_install_function();
414 }
415
416 /// Continue with the installation, roles and other stuff
417 $module->id = $DB->insert_record('modules', $module);
418
795a08ad 419 /// Install various components
420 update_capabilities($component);
421 events_update_definition($component);
422 message_update_providers($component);
423
424 $endcallback($component, true);
db9d4a3d 425
795a08ad 426 } else if ($currmodule->version < $module->version) {
427 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
428 $startcallback($component, false);
429
430 if (is_readable($fullmod.'/db/upgrade.php')) {
431 require_once($fullmod.'/db/upgrade.php'); // defines new upgrading function
432 $newupgrade_function = 'xmldb_'.$module->name.'_upgrade';
433 $result = $newupgrade_function($currmodule->version, $module);
434 } else {
435 $result = true;
436 }
437
438 $currmodule = $DB->get_record('modules', array('name'=>$module->name));
439 if ($currmodule->version < $module->version) {
440 // store version if not already there
441 upgrade_mod_savepoint($result, $module->version, $mod, false);
442 }
443
444 /// Upgrade various components
445 update_capabilities($component);
446 events_update_definition($component);
447 message_update_providers($component);
448
449 remove_dir($CFG->dataroot.'/cache', true); // flush cache
450
451 $endcallback($component, false);
452
453 } else if ($currmodule->version > $module->version) {
454 throw new downgrade_exception($component, $currmodule->version, $module->version);
455 }
456 }
457}
db9d4a3d 458
db9d4a3d 459
795a08ad 460/**
461 * This function finds all available blocks and install them
462 * into blocks table or do all the upgrade process if newer.
463 */
464function upgrade_plugins_blocks($startcallback, $endcallback) {
465 global $CFG, $DB;
466
795a08ad 467 require_once($CFG->dirroot.'/blocks/moodleblock.class.php');
468
469 $blocktitles = array(); // we do not want duplicate titles
470
471 //Is this a first install
472 $first_install = null;
473
474 $blocks = get_list_of_plugins('blocks');
475
476 foreach ($blocks as $blockname) {
477
478 if (is_null($first_install)) {
479 $first_install = ($DB->count_records('block') == 0);
480 }
481
482 if ($blockname == 'NEWBLOCK') { // Someone has unzipped the template, ignore it
483 continue;
db9d4a3d 484 }
485
795a08ad 486 $fullblock = $CFG->dirroot.'/blocks/'.$blockname;
487 $component = 'block/'.$blockname;
db9d4a3d 488
795a08ad 489 if (!is_readable($fullblock.'/block_'.$blockname.'.php')) {
490 throw new plugin_defective_exception('block/'.$blockname, 'Missing main block class file.');
db9d4a3d 491 }
795a08ad 492 require_once($fullblock.'/block_'.$blockname.'.php');
db9d4a3d 493
795a08ad 494 $classname = 'block_'.$blockname;
495
496 if (!class_exists($classname)) {
497 throw new plugin_defective_exception($component, 'Can not load main class.');
498 }
499
500 $blockobj = new $classname; // This is what we 'll be testing
501 $blocktitle = $blockobj->get_title();
502
503 // OK, it's as we all hoped. For further tests, the object will do them itself.
504 if (!$blockobj->_self_test()) {
505 throw new plugin_defective_exception($component, 'Self test failed.');
506 }
507
508 $block = new object(); // This may be used to update the db below
509 $block->name = $blockname; // The name MUST match the directory
510 $block->version = $blockobj->get_version();
511 $block->cron = !empty($blockobj->cron) ? $blockobj->cron : 0;
512 $block->multiple = $blockobj->instance_allow_multiple() ? 1 : 0;
513
514 if (empty($block->version)) {
515 throw new plugin_defective_exception($component, 'Missing block version.');
516 }
517
518 $currblock = $DB->get_record('block', array('name'=>$block->name));
519
520 if (empty($currblock->version)) { // block not installed yet, so install it
521 // If it allows multiples, start with it enabled
522
523 $conflictblock = array_search($blocktitle, $blocktitles);
524 if ($conflictblock !== false) {
525 // Duplicate block titles are not allowed, they confuse people
526 // AND PHP's associative arrays ;)
527 throw new plugin_defective_exception($component, get_string('blocknameconflict', '', (object)array('name'=>$block->name, 'conflict'=>$conflictblock)));
528 }
529 $startcallback($component, true);
530
531 if (file_exists($fullblock.'/db/install.xml')) {
532 $DB->get_manager()->install_from_xmldb_file($fullblock.'/db/install.xml');
533 }
534 $block->id = $DB->insert_record('block', $block);
535
536 if (file_exists($fullblock.'/db/install.php')) {
537 require_once($fullblock.'/db/install.php');
538 $post_install_function = 'xmldb_block_'.$blockname.'_install';;
539 $post_install_function();
540 }
541
542 $blocktitles[$block->name] = $blocktitle;
543
544 // Install various components
545 update_capabilities($component);
546 events_update_definition($component);
547 message_update_providers($component);
548
549 $endcallback($component, true);
550
551 } else if ($currblock->version < $block->version) {
552 $startcallback($component, false);
553
554 if (is_readable($fullblock.'/db/upgrade.php')) {
555 require_once($fullblock.'/db/upgrade.php'); // defines new upgrading function
556 $newupgrade_function = 'xmldb_block_'.$blockname.'_upgrade';
557 $result = $newupgrade_function($currblock->version, $block);
558 } else {
559 $result = true;
560 }
561
562 $currblock = $DB->get_record('block', array('name'=>$block->name));
563 if ($currblock->version < $block->version) {
564 // store version if not already there
565 upgrade_block_savepoint($result, $block->version, $block->name, false);
566 }
567
568 if ($currblock->cron != $block->cron) {
569 // update cron flag if needed
570 $currblock->cron = $block->cron;
571 $DB->update_record('block', $currblock);
572 }
573
574 // Upgrade various componebts
575 events_update_definition($component);
576 update_capabilities($component);
577 message_update_providers($component);
578
579 $endcallback($component, false);
580
581 } else if ($currblock->version > $block->version) {
582 throw new downgrade_exception($component, $currblock->version, $block->version);
583 }
584 }
585
586
587 // Finally, if we are in the first_install of BLOCKS setup frontpage and admin page blocks
588 if ($first_install) {
795a08ad 589 //Iterate over each course - there should be only site course here now
590 if ($courses = $DB->get_records('course')) {
591 foreach ($courses as $course) {
9d1d606e 592 blocks_add_default_course_blocks($course);
db9d4a3d 593 }
594 }
795a08ad 595
9d1d606e 596 blocks_add_default_system_blocks();
795a08ad 597 }
598}
599
600/**
601 * This function checks to see whether local database customisations are up-to-date
602 * by comparing $CFG->local_version to the variable $local_version defined in
603 * local/version.php. If not, it looks for a function called 'xmldb_local_upgrade'
604 * in a file called 'local/db/upgrade.php', and if it's there calls it with the
605 * appropiate $oldversion parameter. Then it updates $CFG->local_version.
606 *
607 * @uses $CFG
608 */
609function upgrade_local_db($startcallback, $endcallback) {
610 global $CFG, $DB;
611
612 // if we don't have code version, just return false
613 if (!file_exists($CFG->dirroot.'/local/version.php')) {
614 return;
615 }
616
617 $local_version = null;
618 require($CFG->dirroot.'/local/version.php'); // Get code versions
619
620 if (empty($CFG->local_version)) { // install
621 $startcallback('local', true);
622
623 if (file_exists($CFG->dirroot.'/local/db/install.php')) {
624 require_once($CFG->dirroot.'/local/db/install.php');
625 xmldb_local_install();
626 }
627 set_config('local_version', $local_version);
628
629 /// Install various components
630 events_update_definition('local');
631 update_capabilities('local');
632 message_update_providers('local');
633
634 $endcallback('local', true);
635
636 } else if ($local_version > $CFG->local_version) { // upgrade!
637 $startcallback('local', false);
638
639 if (file_exists($CFG->dirroot.'/local/db/upgrade.php')) {
640 require_once($CFG->dirroot.'/local/db/upgrade.php');
641 xmldb_local_upgrade($CFG->local_version);
642 }
643 set_config('local_version', $local_version);
644
645 /// Upgrade various components
646 events_update_definition('local');
647 update_capabilities('local');
648 message_update_providers('local');
649
650 $endcallback('local', false);
651
652 } else if ($local_version < $CFG->local_version) {
653 throw new downgrade_exception('local', $CFG->local_version, $local_version);
db9d4a3d 654 }
655}
656
657
658////////////////////////////////////////////////
659/// upgrade logging functions
660////////////////////////////////////////////////
661
795a08ad 662function upgrade_handle_exception($ex, $plugin=null) {
663 global $CFG;
664
665 if ($ex instanceof moodle_exception) {
666 $details = get_string($ex->errorcode, $ex->module, $ex->a)."<br />debugging:".$ex->debuginfo;
667 } else {
668 $details = get_string('generalexceptionmessage', 'error', $ex->getMessage());
669 }
670 $info = "Exception: ".get_class($ex);
671 $backtrace = $ex->getTrace();
672 $place = array('file'=>$ex->getFile(), 'line'=>$ex->getLine(), 'exception'=>get_class($ex));
673 array_unshift($backtrace, $place);
674
675 /// first log upgrade error
676 upgrade_log(UPGRADE_LOG_ERROR, $plugin, $info, $details, $backtrace);
677
678 // always turn on debugging - admins need to know what is going on
679 $CFG->debug = DEBUG_DEVELOPER;
680
681 // now print the exception info as usually
682 if ($ex instanceof moodle_exception) {
683 _print_normal_error($ex->errorcode, $ex->module, $ex->a, $ex->link, $backtrace, $ex->debuginfo);
684 } else {
685 _print_normal_error('generalexceptionmessage', 'error', $ex->getMessage(), '', $backtrace);
686 }
687
688 die; // not reached
db9d4a3d 689}
690
691/**
692 * Adds log entry into upgrade_log table
693 *
694 * @param int $type UPGRADE_LOG_NORMAL, UPGRADE_LOG_NOTICE or UPGRADE_LOG_ERROR
695 * @param string $plugin plugin or null if main
696 * @param string $info short description text of log entry
697 * @param string $details long problem description
698 * @param string $backtrace string used for errors only
699 * @return void
700 */
701function upgrade_log($type, $plugin, $info, $details=null, $backtrace=null) {
702 global $DB, $USER, $CFG;
703
795a08ad 704 $plugin = ($plugin==='moodle') ? null : $plugin;
705
706 $backtrace = print_backtrace($backtrace, true);
db9d4a3d 707
708 $version = null;
709
710 //first try to find out current version number
795a08ad 711 if (empty($plugin) or $plugin === 'moodle') {
db9d4a3d 712 //main
713 $version = $CFG->version;
714
795a08ad 715 } else if ($plugin === 'local') {
716 //customisation
717 $version = $CFG->local_version;
718
719 } else if (strpos($plugin, 'mod/') === 0) {
db9d4a3d 720 try {
721 $modname = substr($plugin, strlen('mod/'));
722 $version = $DB->get_field('modules', 'version', array('name'=>$modname));
795a08ad 723 $version = ($version === false) ? null : $version;
db9d4a3d 724 } catch (Exception $ignored) {
725 }
726
795a08ad 727 } else if (strpos($plugin, 'block/') === 0) {
db9d4a3d 728 try {
795a08ad 729 $blockname = substr($plugin, strlen('block/'));
db9d4a3d 730 if ($block = $DB->get_record('block', array('name'=>$blockname))) {
731 $version = $block->version;
732 }
733 } catch (Exception $ignored) {
734 }
795a08ad 735
736 } else {
737 $pluginversion = get_config(str_replace('/', '_', $plugin), 'version');
738 if (!empty($pluginversion)) {
739 $version = $pluginversion;
740 }
db9d4a3d 741 }
742
743 $log = new object();
744 $log->type = $type;
745 $log->plugin = $plugin;
746 $log->version = $version;
747 $log->info = $info;
748 $log->details = $details;
749 $log->backtrace = $backtrace;
750 $log->userid = $USER->id;
751 $log->timemodified = time();
db9d4a3d 752 try {
753 $DB->insert_record('upgrade_log', $log);
754 } catch (Exception $ignored) {
795a08ad 755 // possible during install or 2.0 upgrade
db9d4a3d 756 }
757}
758
759/**
760 * Marks start of upgrade, blocks any other access to site.
761 * The upgrade is finished at the end of script or after timeout.
762 */
763function upgrade_started($preinstall=false) {
c13a5e71 764 global $CFG, $DB, $PAGE;
db9d4a3d 765
766 static $started = false;
767
768 if ($preinstall) {
769 ignore_user_abort(true);
770 upgrade_setup_debug(true);
771
772 } else if ($started) {
773 upgrade_set_timeout(120);
774
775 } else {
c13a5e71 776 if (!CLI_SCRIPT and !$PAGE->headerprinted) {
db9d4a3d 777 $strupgrade = get_string('upgradingversion', 'admin');
778
9ace5094 779 print_header($strupgrade.' - Moodle '.$CFG->target_release, $strupgrade,
db9d4a3d 780 build_navigation(array(array('name' => $strupgrade, 'link' => null, 'type' => 'misc'))), '',
781 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
782 }
783
784 ignore_user_abort(true);
785 register_shutdown_function('upgrade_finished_handler');
786 upgrade_setup_debug(true);
787 set_config('upgraderunning', time()+300);
788 $started = true;
789 }
790}
791
792/**
793 * Internal function - executed if upgrade interruped.
794 */
795function upgrade_finished_handler() {
796 upgrade_finished();
797}
798
799/**
800 * Indicates upgrade is finished.
801 *
802 * This function may be called repeatedly.
803 */
804function upgrade_finished($continueurl=null) {
805 global $CFG, $DB;
806
807 if (!empty($CFG->upgraderunning)) {
808 unset_config('upgraderunning');
809 upgrade_setup_debug(false);
810 ignore_user_abort(false);
811 if ($continueurl) {
812 print_continue($continueurl);
9ace5094 813 print_footer('upgrade');
db9d4a3d 814 die;
815 }
816 }
817}
818
819function upgrade_setup_debug($starting) {
820 global $CFG, $DB;
821
822 static $originaldebug = null;
823
824 if ($starting) {
825 if ($originaldebug === null) {
826 $originaldebug = $DB->get_debug();
827 }
828 if (!empty($CFG->upgradeshowsql)) {
829 $DB->set_debug(true);
830 }
831 } else {
832 $DB->set_debug($originaldebug);
833 }
834}
835
90509582 836function print_upgrade_reload($url) {
837 global $CFG;
838
839 echo "<br />";
840 echo '<div class="continuebutton">';
841 echo '<a href="'.$url.'" title="'.get_string('reload').'" ><img src="'.$CFG->pixpath.'/i/reload.gif" alt="" /> '.get_string('reload').'</a>';
842 echo '</div><br />';
843}
844
db9d4a3d 845function print_upgrade_separator() {
846 if (!CLI_SCRIPT) {
847 echo '<hr />';
848 }
849}
850
795a08ad 851/**
852 * Default start upgrade callback
853 * @param string $plugin
854 * @param bool $installation true if installation, false menas upgrade
855 */
856function print_upgrade_part_start($plugin, $installation) {
857 if (empty($plugin) or $plugin == 'moodle') {
858 upgrade_started($installation); // does not store upgrade running flag yet
859 print_heading(get_string('coresystem'));
860 } else {
861 upgrade_started();
862 print_heading($plugin);
863 }
864 if ($installation) {
865 if (empty($plugin) or $plugin == 'moodle') {
866 // no need to log - log table not yet there ;-)
867 } else {
868 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin installation');
869 }
870 } else {
871 if (empty($plugin) or $plugin == 'moodle') {
872 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting core upgrade');
873 } else {
874 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin upgrade');
875 }
876 }
877}
878
879/**
880 * Default end upgrade callback
881 * @param string $plugin
882 * @param bool $installation true if installation, false menas upgrade
883 */
884function print_upgrade_part_end($plugin, $installation) {
885 upgrade_started();
886 if ($installation) {
887 if (empty($plugin) or $plugin == 'moodle') {
888 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core installed');
889 } else {
890 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin installed');
891 }
892 } else {
893 if (empty($plugin) or $plugin == 'moodle') {
894 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core upgraded');
895 } else {
896 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin upgraded');
897 }
898 }
899 notify(get_string('success'), 'notifysuccess');
900 print_upgrade_separator();
901}
db9d4a3d 902
96db14f9 903/**
904 * Silent start upgrade callback - does not output anything
905 * @param string $plugin
906 * @param bool $installation true if installation, false menas upgrade
907 */
908function silent_upgrade_part_start($plugin, $installation) {
909 if (empty($plugin) or $plugin == 'moodle') {
910 upgrade_started($installation); // does not store upgrade running flag yet
911 } else {
912 upgrade_started();
913 }
914 if ($installation) {
915 if (empty($plugin) or $plugin == 'moodle') {
916 // no need to log - log table not yet there ;-)
917 } else {
918 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin installation');
919 }
920 } else {
921 if (empty($plugin) or $plugin == 'moodle') {
922 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting core upgrade');
923 } else {
924 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin upgrade');
925 }
926 }
927}
928
929/**
930 * Silent end upgrade callback - does not output anything
931 * @param string $plugin
932 * @param bool $installation true if installation, false menas upgrade
933 */
934function silent_upgrade_part_end($plugin, $installation) {
935 upgrade_started();
936 if ($installation) {
937 if (empty($plugin) or $plugin == 'moodle') {
938 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core installed');
939 } else {
940 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin installed');
941 }
942 } else {
943 if (empty($plugin) or $plugin == 'moodle') {
944 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core upgraded');
945 } else {
946 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin upgraded');
947 }
948 }
949}
950
db9d4a3d 951function upgrade_get_javascript() {
952 global $CFG;
2d6b0b04 953 return '<script type="text/javascript" src="'.$CFG->wwwroot.'/lib/scroll_to_page_end.js"></script>';
db9d4a3d 954}
955
956
957/**
958 * Try to upgrade the given language pack (or current language)
db9d4a3d 959 */
960function upgrade_language_pack($lang='') {
961 global $CFG;
962
963 if (empty($lang)) {
964 $lang = current_language();
965 }
966
967 if ($lang == 'en_utf8') {
968 return true; // Nothing to do
969 }
970
551fe0e5 971 upgrade_started(false);
972 print_heading(get_string('langimport', 'admin').': '.$lang);
db9d4a3d 973
974 @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
975 @mkdir ($CFG->dataroot.'/lang/');
976
977 require_once($CFG->libdir.'/componentlib.class.php');
978
979 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
980 $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
981
982 if ($status == COMPONENT_INSTALLED) {
db9d4a3d 983 @unlink($CFG->dataroot.'/cache/languages');
551fe0e5 984 if ($parentlang = get_parent_language($lang)) {
985 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $parentlang.'.zip', 'languages.md5', 'lang')) {
986 $cd->install();
987 }
988 }
989 notify(get_string('success'), 'notifysuccess');
db9d4a3d 990 }
991 }
992
551fe0e5 993 print_upgrade_separator();
db9d4a3d 994}