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