MDL-20273 updated web services and functions description tables , includes indexes...
[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);
45440ceb 46 parent::__construct('upgradeerror', 'admin', "$CFG->wwwroot/$CFG->admin/index.php", $a);
795a08ad 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;
17da2e6f 80 $a->requiremoodle = $requiremoodle;
795a08ad 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) {
520cea92 147 throw new upgrade_exception(null, $version);
795a08ad 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) {
520cea92 183 throw new upgrade_exception("mod_$modname", $version);
795a08ad 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
520cea92 192 throw new downgrade_exception("mod_$modname", $module->version, $version);
db9d4a3d 193 }
795a08ad 194 $module->version = $version;
195 $DB->update_record('modules', $module);
520cea92 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) {
520cea92 223 throw new upgrade_exception("block_$blockname", $version);
795a08ad 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
520cea92 232 throw new downgrade_exception("block_$blockname", $block->version, $version);
db9d4a3d 233 }
795a08ad 234 $block->version = $version;
235 $DB->update_record('block', $block);
520cea92 236 upgrade_log(UPGRADE_LOG_NORMAL, "block_$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 */
17da2e6f 259function upgrade_plugin_savepoint($result, $version, $type, $plugin, $allowabort=true) {
260 $component = $type.'_'.$plugin;
261
795a08ad 262 if (!$result) {
17da2e6f 263 throw new upgrade_exception($component, $version);
db9d4a3d 264 }
265
17da2e6f 266 $installedversion = get_config($component, 'version');
795a08ad 267 if ($installedversion >= $version) {
268 // Something really wrong is going on in the upgrade script
269 throw new downgrade_exception($component, $installedversion, $version);
270 }
17da2e6f 271 set_config('version', $version, $component);
795a08ad 272 upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached');
273
db9d4a3d 274 // Reset upgrade timeout to default
275 upgrade_set_timeout();
276
277 // This is a safe place to stop upgrades if user aborts page loading
278 if ($allowabort and connection_aborted()) {
279 die;
280 }
281}
282
283
284/**
285 * Upgrade plugins
db9d4a3d 286 * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
17da2e6f 287 * return void
db9d4a3d 288 */
17da2e6f 289function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
db9d4a3d 290 global $CFG, $DB;
291
292/// special cases
293 if ($type === 'mod') {
194cdca8 294 return upgrade_plugins_modules($startcallback, $endcallback, $verbose);
795a08ad 295 } else if ($type === 'block') {
194cdca8 296 return upgrade_plugins_blocks($startcallback, $endcallback, $verbose);
db9d4a3d 297 }
298
17da2e6f 299 $plugs = get_plugin_list($type);
db9d4a3d 300
17da2e6f 301 foreach ($plugs as $plug=>$fullplug) {
302 $component = $type.'_'.$plug; // standardised plugin name
db9d4a3d 303
795a08ad 304 if (!is_readable($fullplug.'/version.php')) {
305 continue;
db9d4a3d 306 }
307
795a08ad 308 $plugin = new object();
309 require($fullplug.'/version.php'); // defines $plugin with version etc
db9d4a3d 310
795a08ad 311 if (empty($plugin->version)) {
312 throw new plugin_defective_exception($component, 'Missing version value in version.php');
db9d4a3d 313 }
314
17da2e6f 315 $plugin->name = $plug;
316 $plugin->fullname = $component;
795a08ad 317
318
db9d4a3d 319 if (!empty($plugin->requires)) {
320 if ($plugin->requires > $CFG->version) {
795a08ad 321 throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires);
db9d4a3d 322 }
323 }
324
9b683d13 325 // try to recover from interrupted install.php if needed
326 if (file_exists($fullplug.'/db/install.php')) {
327 if (get_config($plugin->fullname, 'installrunning')) {
328 require_once($fullplug.'/db/install.php');
329 $recover_install_function = 'xmldb_'.$plugin->fullname.'_install_recovery';
330 if (function_exists($recover_install_function)) {
331 $startcallback($component, true, $verbose);
332 $recover_install_function();
333 unset_config('installrunning', 'block_'.$plugin->fullname);
334 update_capabilities($component);
335 events_update_definition($component);
336 message_update_providers($component);
337 $endcallback($component, true, $verbose);
338 }
339 }
340 }
db9d4a3d 341
9b683d13 342 $installedversion = get_config($plugin->fullname, 'version');
795a08ad 343 if (empty($installedversion)) { // new installation
194cdca8 344 $startcallback($component, true, $verbose);
db9d4a3d 345
795a08ad 346 /// Install tables if defined
347 if (file_exists($fullplug.'/db/install.xml')) {
348 $DB->get_manager()->install_from_xmldb_file($fullplug.'/db/install.xml');
db9d4a3d 349 }
9b683d13 350
351 /// store version
352 upgrade_plugin_savepoint(true, $plugin->version, $type, $plug, false);
353
795a08ad 354 /// execute post install file
355 if (file_exists($fullplug.'/db/install.php')) {
356 require_once($fullplug.'/db/install.php');
9b683d13 357 set_config('installrunning', 1, 'block_'.$plugin->fullname);
795a08ad 358 $post_install_function = 'xmldb_'.$plugin->fullname.'_install';;
359 $post_install_function();
9b683d13 360 unset_config('installrunning', 'block_'.$plugin->fullname);
795a08ad 361 }
362
795a08ad 363 /// Install various components
364 update_capabilities($component);
365 events_update_definition($component);
366 message_update_providers($component);
367
194cdca8 368 $endcallback($component, true, $verbose);
795a08ad 369
370 } else if ($installedversion < $plugin->version) { // upgrade
371 /// Run the upgrade function for the plugin.
194cdca8 372 $startcallback($component, false, $verbose);
795a08ad 373
374 if (is_readable($fullplug.'/db/upgrade.php')) {
375 require_once($fullplug.'/db/upgrade.php'); // defines upgrading function
376
377 $newupgrade_function = 'xmldb_'.$plugin->fullname.'_upgrade';
378 $result = $newupgrade_function($installedversion);
379 } else {
380 $result = true;
381 }
382
383 $installedversion = get_config($plugin->fullname, 'version');
384 if ($installedversion < $plugin->version) {
385 // store version if not already there
386 upgrade_plugin_savepoint($result, $plugin->version, $type, $plug, false);
387 }
388
389 /// Upgrade various components
390 update_capabilities($component);
391 events_update_definition($component);
392 message_update_providers($component);
393
194cdca8 394 $endcallback($component, false, $verbose);
795a08ad 395
396 } else if ($installedversion > $plugin->version) {
397 throw new downgrade_exception($component, $installedversion, $plugin->version);
db9d4a3d 398 }
399 }
db9d4a3d 400}
401
402/**
403 * Find and check all modules and load them up or upgrade them if necessary
72fb21b6 404 *
405 * @global object
406 * @global object
db9d4a3d 407 */
194cdca8 408function upgrade_plugins_modules($startcallback, $endcallback, $verbose) {
db9d4a3d 409 global $CFG, $DB;
410
17da2e6f 411 $mods = get_plugin_list('mod');
db9d4a3d 412
17da2e6f 413 foreach ($mods as $mod=>$fullmod) {
db9d4a3d 414
415 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
416 continue;
417 }
418
17da2e6f 419 $component = 'mod_'.$mod;
db9d4a3d 420
795a08ad 421 if (!is_readable($fullmod.'/version.php')) {
422 throw new plugin_defective_exception($component, 'Missing version.php');
db9d4a3d 423 }
424
795a08ad 425 $module = new object();
426 require($fullmod .'/version.php'); // defines $module with version etc
db9d4a3d 427
795a08ad 428 if (empty($module->version)) {
c1fe2368 429 if (isset($module->version)) {
430 // Version is empty but is set - it means its value is 0 or ''. Let us skip such module.
431 // This is inteded for developers so they can work on the early stages of the module.
432 continue;
433 }
795a08ad 434 throw new plugin_defective_exception($component, 'Missing version value in version.php');
db9d4a3d 435 }
436
437 if (!empty($module->requires)) {
438 if ($module->requires > $CFG->version) {
795a08ad 439 throw new upgrade_requires_exception($component, $module->version, $CFG->version, $module->requires);
db9d4a3d 440 }
441 }
442
443 $module->name = $mod; // The name MUST match the directory
444
795a08ad 445 $currmodule = $DB->get_record('modules', array('name'=>$module->name));
db9d4a3d 446
9b683d13 447 if (file_exists($fullmod.'/db/install.php')) {
448 if (get_config($module->name, 'installrunning')) {
449 require_once($fullmod.'/db/install.php');
450 $recover_install_function = 'xmldb_'.$module->name.'_install_recovery';
451 if (function_exists($recover_install_function)) {
452 $startcallback($component, true, $verbose);
453 $recover_install_function();
454 unset_config('installrunning', $module->name);
455 // Install various components too
456 update_capabilities($component);
457 events_update_definition($component);
458 message_update_providers($component);
459 $endcallback($component, true, $verbose);
460 }
461 }
462 }
463
795a08ad 464 if (empty($currmodule->version)) {
194cdca8 465 $startcallback($component, true, $verbose);
db9d4a3d 466
795a08ad 467 /// Execute install.xml (XMLDB) - must be present in all modules
468 $DB->get_manager()->install_from_xmldb_file($fullmod.'/db/install.xml');
db9d4a3d 469
2e3da297 470 /// Add record into modules table - may be needed in install.php already
471 $module->id = $DB->insert_record('modules', $module);
472
db9d4a3d 473 /// Post installation hook - optional
474 if (file_exists("$fullmod/db/install.php")) {
475 require_once("$fullmod/db/install.php");
9b683d13 476 // Set installation running flag, we need to recover after exception or error
477 set_config('installrunning', 1, $module->name);
db9d4a3d 478 $post_install_function = 'xmldb_'.$module->name.'_install';;
479 $post_install_function();
9b683d13 480 unset_config('installrunning', $module->name);
db9d4a3d 481 }
482
795a08ad 483 /// Install various components
484 update_capabilities($component);
485 events_update_definition($component);
486 message_update_providers($component);
487
194cdca8 488 $endcallback($component, true, $verbose);
db9d4a3d 489
795a08ad 490 } else if ($currmodule->version < $module->version) {
491 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
194cdca8 492 $startcallback($component, false, $verbose);
795a08ad 493
494 if (is_readable($fullmod.'/db/upgrade.php')) {
495 require_once($fullmod.'/db/upgrade.php'); // defines new upgrading function
496 $newupgrade_function = 'xmldb_'.$module->name.'_upgrade';
497 $result = $newupgrade_function($currmodule->version, $module);
498 } else {
499 $result = true;
500 }
501
502 $currmodule = $DB->get_record('modules', array('name'=>$module->name));
503 if ($currmodule->version < $module->version) {
504 // store version if not already there
505 upgrade_mod_savepoint($result, $module->version, $mod, false);
506 }
507
508 /// Upgrade various components
509 update_capabilities($component);
510 events_update_definition($component);
511 message_update_providers($component);
512
513 remove_dir($CFG->dataroot.'/cache', true); // flush cache
514
194cdca8 515 $endcallback($component, false, $verbose);
795a08ad 516
517 } else if ($currmodule->version > $module->version) {
518 throw new downgrade_exception($component, $currmodule->version, $module->version);
519 }
520 }
521}
db9d4a3d 522
db9d4a3d 523
795a08ad 524/**
525 * This function finds all available blocks and install them
526 * into blocks table or do all the upgrade process if newer.
72fb21b6 527 *
528 * @global object
529 * @global object
795a08ad 530 */
194cdca8 531function upgrade_plugins_blocks($startcallback, $endcallback, $verbose) {
795a08ad 532 global $CFG, $DB;
533
795a08ad 534 require_once($CFG->dirroot.'/blocks/moodleblock.class.php');
535
536 $blocktitles = array(); // we do not want duplicate titles
537
538 //Is this a first install
539 $first_install = null;
540
17da2e6f 541 $blocks = get_plugin_list('block');
795a08ad 542
17da2e6f 543 foreach ($blocks as $blockname=>$fullblock) {
795a08ad 544
545 if (is_null($first_install)) {
546 $first_install = ($DB->count_records('block') == 0);
547 }
548
549 if ($blockname == 'NEWBLOCK') { // Someone has unzipped the template, ignore it
550 continue;
db9d4a3d 551 }
552
17da2e6f 553 $component = 'block_'.$blockname;
db9d4a3d 554
795a08ad 555 if (!is_readable($fullblock.'/block_'.$blockname.'.php')) {
556 throw new plugin_defective_exception('block/'.$blockname, 'Missing main block class file.');
db9d4a3d 557 }
795a08ad 558 require_once($fullblock.'/block_'.$blockname.'.php');
db9d4a3d 559
795a08ad 560 $classname = 'block_'.$blockname;
561
562 if (!class_exists($classname)) {
563 throw new plugin_defective_exception($component, 'Can not load main class.');
564 }
565
566 $blockobj = new $classname; // This is what we 'll be testing
567 $blocktitle = $blockobj->get_title();
568
569 // OK, it's as we all hoped. For further tests, the object will do them itself.
570 if (!$blockobj->_self_test()) {
571 throw new plugin_defective_exception($component, 'Self test failed.');
572 }
573
574 $block = new object(); // This may be used to update the db below
575 $block->name = $blockname; // The name MUST match the directory
576 $block->version = $blockobj->get_version();
577 $block->cron = !empty($blockobj->cron) ? $blockobj->cron : 0;
578 $block->multiple = $blockobj->instance_allow_multiple() ? 1 : 0;
579
580 if (empty($block->version)) {
581 throw new plugin_defective_exception($component, 'Missing block version.');
582 }
583
584 $currblock = $DB->get_record('block', array('name'=>$block->name));
585
9b683d13 586 if (file_exists($fullblock.'/db/install.php')) {
587 if (get_config('block_'.$blockname, 'installrunning')) {
588 require_once($fullblock.'/db/install.php');
589 $recover_install_function = 'xmldb_block_'.$blockname.'_install_recovery';
590 if (function_exists($recover_install_function)) {
591 $startcallback($component, true, $verbose);
592 $recover_install_function();
593 unset_config('installrunning', 'block_'.$blockname);
594 // Install various components
595 update_capabilities($component);
596 events_update_definition($component);
597 message_update_providers($component);
598 $endcallback($component, true, $verbose);
599 }
600 }
601 }
602
795a08ad 603 if (empty($currblock->version)) { // block not installed yet, so install it
604 // If it allows multiples, start with it enabled
605
606 $conflictblock = array_search($blocktitle, $blocktitles);
607 if ($conflictblock !== false) {
608 // Duplicate block titles are not allowed, they confuse people
609 // AND PHP's associative arrays ;)
610 throw new plugin_defective_exception($component, get_string('blocknameconflict', '', (object)array('name'=>$block->name, 'conflict'=>$conflictblock)));
611 }
194cdca8 612 $startcallback($component, true, $verbose);
795a08ad 613
614 if (file_exists($fullblock.'/db/install.xml')) {
615 $DB->get_manager()->install_from_xmldb_file($fullblock.'/db/install.xml');
616 }
617 $block->id = $DB->insert_record('block', $block);
618
619 if (file_exists($fullblock.'/db/install.php')) {
620 require_once($fullblock.'/db/install.php');
9b683d13 621 // Set installation running flag, we need to recover after exception or error
622 set_config('installrunning', 1, 'block_'.$blockname);
795a08ad 623 $post_install_function = 'xmldb_block_'.$blockname.'_install';;
624 $post_install_function();
9b683d13 625 unset_config('installrunning', 'block_'.$blockname);
795a08ad 626 }
627
628 $blocktitles[$block->name] = $blocktitle;
629
630 // Install various components
631 update_capabilities($component);
632 events_update_definition($component);
633 message_update_providers($component);
634
194cdca8 635 $endcallback($component, true, $verbose);
795a08ad 636
637 } else if ($currblock->version < $block->version) {
194cdca8 638 $startcallback($component, false, $verbose);
795a08ad 639
640 if (is_readable($fullblock.'/db/upgrade.php')) {
641 require_once($fullblock.'/db/upgrade.php'); // defines new upgrading function
642 $newupgrade_function = 'xmldb_block_'.$blockname.'_upgrade';
643 $result = $newupgrade_function($currblock->version, $block);
644 } else {
645 $result = true;
646 }
647
648 $currblock = $DB->get_record('block', array('name'=>$block->name));
649 if ($currblock->version < $block->version) {
650 // store version if not already there
651 upgrade_block_savepoint($result, $block->version, $block->name, false);
652 }
653
654 if ($currblock->cron != $block->cron) {
655 // update cron flag if needed
656 $currblock->cron = $block->cron;
657 $DB->update_record('block', $currblock);
658 }
659
660 // Upgrade various componebts
795a08ad 661 update_capabilities($component);
17da2e6f 662 events_update_definition($component);
795a08ad 663 message_update_providers($component);
664
194cdca8 665 $endcallback($component, false, $verbose);
795a08ad 666
667 } else if ($currblock->version > $block->version) {
668 throw new downgrade_exception($component, $currblock->version, $block->version);
669 }
670 }
671
672
673 // Finally, if we are in the first_install of BLOCKS setup frontpage and admin page blocks
674 if ($first_install) {
795a08ad 675 //Iterate over each course - there should be only site course here now
676 if ($courses = $DB->get_records('course')) {
677 foreach ($courses as $course) {
9d1d606e 678 blocks_add_default_course_blocks($course);
db9d4a3d 679 }
680 }
795a08ad 681
9d1d606e 682 blocks_add_default_system_blocks();
795a08ad 683 }
684}
685
72fb21b6 686/**
687 * upgrade logging functions
72fb21b6 688 */
fd1a792e 689function upgrade_handle_exception($ex, $plugin = null) {
690 default_exception_handler($ex, true, $plugin);
db9d4a3d 691}
692
693/**
694 * Adds log entry into upgrade_log table
695 *
72fb21b6 696 * @global object
697 * @global object
698 * @global object
db9d4a3d 699 * @param int $type UPGRADE_LOG_NORMAL, UPGRADE_LOG_NOTICE or UPGRADE_LOG_ERROR
700 * @param string $plugin plugin or null if main
701 * @param string $info short description text of log entry
702 * @param string $details long problem description
703 * @param string $backtrace string used for errors only
704 * @return void
705 */
706function upgrade_log($type, $plugin, $info, $details=null, $backtrace=null) {
707 global $DB, $USER, $CFG;
708
795a08ad 709 $plugin = ($plugin==='moodle') ? null : $plugin;
710
34a2777c 711 $backtrace = format_backtrace($backtrace, true);
db9d4a3d 712
713 $version = null;
714
715 //first try to find out current version number
795a08ad 716 if (empty($plugin) or $plugin === 'moodle') {
db9d4a3d 717 //main
718 $version = $CFG->version;
719
795a08ad 720 } else if ($plugin === 'local') {
721 //customisation
722 $version = $CFG->local_version;
723
724 } else if (strpos($plugin, 'mod/') === 0) {
db9d4a3d 725 try {
726 $modname = substr($plugin, strlen('mod/'));
727 $version = $DB->get_field('modules', 'version', array('name'=>$modname));
795a08ad 728 $version = ($version === false) ? null : $version;
db9d4a3d 729 } catch (Exception $ignored) {
730 }
731
795a08ad 732 } else if (strpos($plugin, 'block/') === 0) {
db9d4a3d 733 try {
795a08ad 734 $blockname = substr($plugin, strlen('block/'));
db9d4a3d 735 if ($block = $DB->get_record('block', array('name'=>$blockname))) {
736 $version = $block->version;
737 }
738 } catch (Exception $ignored) {
739 }
795a08ad 740
741 } else {
742 $pluginversion = get_config(str_replace('/', '_', $plugin), 'version');
743 if (!empty($pluginversion)) {
744 $version = $pluginversion;
745 }
db9d4a3d 746 }
747
748 $log = new object();
749 $log->type = $type;
750 $log->plugin = $plugin;
751 $log->version = $version;
752 $log->info = $info;
753 $log->details = $details;
754 $log->backtrace = $backtrace;
755 $log->userid = $USER->id;
756 $log->timemodified = time();
db9d4a3d 757 try {
758 $DB->insert_record('upgrade_log', $log);
759 } catch (Exception $ignored) {
795a08ad 760 // possible during install or 2.0 upgrade
db9d4a3d 761 }
762}
763
764/**
765 * Marks start of upgrade, blocks any other access to site.
766 * The upgrade is finished at the end of script or after timeout.
72fb21b6 767 *
768 * @global object
769 * @global object
770 * @global object
db9d4a3d 771 */
772function upgrade_started($preinstall=false) {
de6d81e6 773 global $CFG, $DB, $PAGE, $OUTPUT;
db9d4a3d 774
775 static $started = false;
776
777 if ($preinstall) {
778 ignore_user_abort(true);
779 upgrade_setup_debug(true);
780
781 } else if ($started) {
782 upgrade_set_timeout(120);
783
784 } else {
c13a5e71 785 if (!CLI_SCRIPT and !$PAGE->headerprinted) {
db9d4a3d 786 $strupgrade = get_string('upgradingversion', 'admin');
d4a03c00 787 $PAGE->set_generaltype('maintenance');
e29380f3 788 upgrade_get_javascript();
de6d81e6 789 $PAGE->set_title($strupgrade.' - Moodle '.$CFG->target_release);
790 $PAGE->set_heading($strupgrade);
791 $PAGE->navbar->add($strupgrade);
792 $PAGE->set_cacheable(false);
793 echo $OUTPUT->header();
db9d4a3d 794 }
795
796 ignore_user_abort(true);
797 register_shutdown_function('upgrade_finished_handler');
798 upgrade_setup_debug(true);
799 set_config('upgraderunning', time()+300);
800 $started = true;
801 }
802}
803
804/**
805 * Internal function - executed if upgrade interruped.
806 */
807function upgrade_finished_handler() {
808 upgrade_finished();
809}
810
811/**
812 * Indicates upgrade is finished.
813 *
814 * This function may be called repeatedly.
72fb21b6 815 *
816 * @global object
817 * @global object
db9d4a3d 818 */
819function upgrade_finished($continueurl=null) {
7e0d6675 820 global $CFG, $DB, $OUTPUT;
db9d4a3d 821
822 if (!empty($CFG->upgraderunning)) {
823 unset_config('upgraderunning');
824 upgrade_setup_debug(false);
825 ignore_user_abort(false);
826 if ($continueurl) {
aa9a6867 827 echo $OUTPUT->continue_button($continueurl);
7e0d6675 828 echo $OUTPUT->footer();
db9d4a3d 829 die;
830 }
831 }
832}
833
72fb21b6 834/**
835 * @global object
836 * @global object
837 */
db9d4a3d 838function upgrade_setup_debug($starting) {
839 global $CFG, $DB;
840
841 static $originaldebug = null;
842
843 if ($starting) {
844 if ($originaldebug === null) {
845 $originaldebug = $DB->get_debug();
846 }
847 if (!empty($CFG->upgradeshowsql)) {
848 $DB->set_debug(true);
849 }
850 } else {
851 $DB->set_debug($originaldebug);
852 }
853}
854
72fb21b6 855/**
856 * @global object
857 */
90509582 858function print_upgrade_reload($url) {
f2a1963c 859 global $OUTPUT;
90509582 860
861 echo "<br />";
862 echo '<div class="continuebutton">';
f2a1963c 863 echo '<a href="'.$url.'" title="'.get_string('reload').'" ><img src="'.$OUTPUT->old_icon_url('i/reload') . '" alt="" /> '.get_string('reload').'</a>';
90509582 864 echo '</div><br />';
865}
866
db9d4a3d 867function print_upgrade_separator() {
868 if (!CLI_SCRIPT) {
869 echo '<hr />';
870 }
871}
872
795a08ad 873/**
874 * Default start upgrade callback
875 * @param string $plugin
876 * @param bool $installation true if installation, false menas upgrade
877 */
194cdca8 878function print_upgrade_part_start($plugin, $installation, $verbose) {
3c159385 879 global $OUTPUT;
795a08ad 880 if (empty($plugin) or $plugin == 'moodle') {
881 upgrade_started($installation); // does not store upgrade running flag yet
194cdca8 882 if ($verbose) {
3c159385 883 echo $OUTPUT->heading(get_string('coresystem'));
194cdca8 884 }
795a08ad 885 } else {
886 upgrade_started();
194cdca8 887 if ($verbose) {
3c159385 888 echo $OUTPUT->heading($plugin);
194cdca8 889 }
795a08ad 890 }
891 if ($installation) {
892 if (empty($plugin) or $plugin == 'moodle') {
893 // no need to log - log table not yet there ;-)
894 } else {
895 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin installation');
896 }
897 } else {
898 if (empty($plugin) or $plugin == 'moodle') {
899 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting core upgrade');
900 } else {
901 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin upgrade');
902 }
903 }
904}
905
906/**
907 * Default end upgrade callback
908 * @param string $plugin
909 * @param bool $installation true if installation, false menas upgrade
910 */
194cdca8 911function print_upgrade_part_end($plugin, $installation, $verbose) {
aa9a6867 912 global $OUTPUT;
795a08ad 913 upgrade_started();
914 if ($installation) {
915 if (empty($plugin) or $plugin == 'moodle') {
916 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core installed');
917 } else {
918 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin installed');
919 }
920 } else {
921 if (empty($plugin) or $plugin == 'moodle') {
922 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core upgraded');
923 } else {
924 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin upgraded');
925 }
926 }
194cdca8 927 if ($verbose) {
aa9a6867 928 echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
194cdca8 929 print_upgrade_separator();
96db14f9 930 }
931}
932
72fb21b6 933/**
934 * @global object
935 */
db9d4a3d 936function upgrade_get_javascript() {
e29380f3 937 global $PAGE;
938 $PAGE->requires->js('lib/javascript-static.js')->at_top_of_body();
939 $PAGE->requires->js_function_call('repeatedly_scroll_to_end')->at_top_of_body();
940 $PAGE->requires->js_function_call('cancel_scroll_to_end')->after_delay(1);
db9d4a3d 941}
942
943
944/**
945 * Try to upgrade the given language pack (or current language)
72fb21b6 946 * @global object
db9d4a3d 947 */
948function upgrade_language_pack($lang='') {
3c159385 949 global $CFG, $OUTPUT;
db9d4a3d 950
951 if (empty($lang)) {
952 $lang = current_language();
953 }
954
955 if ($lang == 'en_utf8') {
956 return true; // Nothing to do
957 }
958
551fe0e5 959 upgrade_started(false);
3c159385 960 echo $OUTPUT->heading(get_string('langimport', 'admin').': '.$lang);
db9d4a3d 961
962 @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
963 @mkdir ($CFG->dataroot.'/lang/');
964
965 require_once($CFG->libdir.'/componentlib.class.php');
966
967 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
968 $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
969
970 if ($status == COMPONENT_INSTALLED) {
db9d4a3d 971 @unlink($CFG->dataroot.'/cache/languages');
551fe0e5 972 if ($parentlang = get_parent_language($lang)) {
973 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $parentlang.'.zip', 'languages.md5', 'lang')) {
974 $cd->install();
975 }
976 }
aa9a6867 977 echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
db9d4a3d 978 }
979 }
980
551fe0e5 981 print_upgrade_separator();
db9d4a3d 982}
8580535b 983
984/**
985 * Install core moodle tables and initialize
986 * @param float $version target version
987 * @param bool $verbose
988 * @return void, may throw exception
989 */
990function install_core($version, $verbose) {
991 global $CFG, $DB;
992
993 try {
c3d0e149 994 set_time_limit(600);
194cdca8 995 print_upgrade_part_start('moodle', true, $verbose); // does not store upgrade running flag
8580535b 996
997 $DB->get_manager()->install_from_xmldb_file("$CFG->libdir/db/install.xml");
998 upgrade_started(); // we want the flag to be stored in config table ;-)
999
1000 // set all core default records and default settings
1001 require_once("$CFG->libdir/db/install.php");
1002 xmldb_main_install();
1003
1004 // store version
1005 upgrade_main_savepoint(true, $version, false);
1006
1007 // Continue with the instalation
1008 events_update_definition('moodle');
1009 message_update_providers('moodle');
8580535b 1010
1011 // Write default settings unconditionlly
1012 admin_apply_default_settings(NULL, true);
1013
194cdca8 1014 print_upgrade_part_end(null, true, $verbose);
8580535b 1015 } catch (exception $ex) {
1016 upgrade_handle_exception($ex);
1017 }
1018}
1019
1020/**
1021 * Upgrade moodle core
1022 * @param float $version target version
1023 * @param bool $verbose
1024 * @return void, may throw exception
1025 */
1026function upgrade_core($version, $verbose) {
1027 global $CFG;
1028
3316fe24 1029 require_once($CFG->libdir.'/db/upgrade.php'); // Defines upgrades
3316fe24 1030
8580535b 1031 try {
1032 // Upgrade current language pack if we can
1033 if (empty($CFG->skiplangupgrade)) {
1034 upgrade_language_pack(false);
1035 }
1036
194cdca8 1037 print_upgrade_part_start('moodle', false, $verbose);
8580535b 1038
17da2e6f 1039 // one time special local migration pre 2.0 upgrade script
1040 if ($version < 2007101600) {
1041 $pre20upgradefile = "$CFG->dirrot/local/upgrade_pre20.php";
1042 if (file_exists($pre20upgradefile)) {
1043 set_time_limit(0);
1044 require($pre20upgradefile);
1045 // reset upgrade timeout to default
1046 upgrade_set_timeout();
1047 }
1048 }
1049
8580535b 1050 $result = xmldb_main_upgrade($CFG->version);
1051 if ($version > $CFG->version) {
1052 // store version if not already there
1053 upgrade_main_savepoint($result, $version, false);
1054 }
1055
1056 // perform all other component upgrade routines
1057 update_capabilities('moodle');
1058 events_update_definition('moodle');
1059 message_update_providers('moodle');
8580535b 1060
1061 remove_dir($CFG->dataroot . '/cache', true); // flush cache
1062
194cdca8 1063 print_upgrade_part_end('moodle', false, $verbose);
8580535b 1064 } catch (Exception $ex) {
1065 upgrade_handle_exception($ex);
1066 }
1067}
1068
1069/**
1070 * Upgrade/install other parts of moodle
1071 * @param bool $verbose
1072 * @return void, may throw exception
1073 */
1074function upgrade_noncore($verbose) {
1075 global $CFG;
1076
8580535b 1077 // upgrade all plugins types
1078 try {
1079 $plugintypes = get_plugin_types();
1080 foreach ($plugintypes as $type=>$location) {
17da2e6f 1081 upgrade_plugins($type, 'print_upgrade_part_start', 'print_upgrade_part_end', $verbose);
8580535b 1082 }
1083 } catch (Exception $ex) {
1084 upgrade_handle_exception($ex);
1085 }
1086
1087 // Check for changes to RPC functions
1088 if ($CFG->mnet_dispatcher_mode != 'off') {
1089 try {
1090 // this needs a full rewrite, sorry to mention that :-(
1091 // we have to make it part of standard WS framework
1092 require_once("$CFG->dirroot/$CFG->admin/mnet/adminlib.php");
1093 upgrade_RPC_functions(); // Return here afterwards
1094 } catch (Exception $ex) {
1095 upgrade_handle_exception($ex);
1096 }
1097 }
8580535b 1098}
3316fe24 1099
1100/**
1101 * Checks if the main tables have been installed yet or not.
1102 * @return bool
1103 */
1104function core_tables_exist() {
1105 global $DB;
1106
1107 if (!$tables = $DB->get_tables() ) { // No tables yet at all.
1108 return false;
9b683d13 1109
3316fe24 1110 } else { // Check for missing main tables
1111 $mtables = array('config', 'course', 'groupings'); // some tables used in 1.9 and 2.0, preferable something from the start and end of install.xml
1112 foreach ($mtables as $mtable) {
1113 if (!in_array($mtable, $tables)) {
1114 return false;
1115 }
1116 }
1117 return true;
9b683d13 1118 }
ba04999c 1119}