|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00027 defined('MOODLE_INTERNAL') || die(); 00028 00030 define('UPGRADE_LOG_NORMAL', 0); 00032 define('UPGRADE_LOG_NOTICE', 1); 00034 define('UPGRADE_LOG_ERROR', 2); 00035 00044 class upgrade_exception extends moodle_exception { 00045 function __construct($plugin, $version, $debuginfo=NULL) { 00046 global $CFG; 00047 $a = (object)array('plugin'=>$plugin, 'version'=>$version); 00048 parent::__construct('upgradeerror', 'admin', "$CFG->wwwroot/$CFG->admin/index.php", $a, $debuginfo); 00049 } 00050 } 00051 00060 class downgrade_exception extends moodle_exception { 00061 function __construct($plugin, $oldversion, $newversion) { 00062 global $CFG; 00063 $plugin = is_null($plugin) ? 'moodle' : $plugin; 00064 $a = (object)array('plugin'=>$plugin, 'oldversion'=>$oldversion, 'newversion'=>$newversion); 00065 parent::__construct('cannotdowngrade', 'debug', "$CFG->wwwroot/$CFG->admin/index.php", $a); 00066 } 00067 } 00068 00075 class upgrade_requires_exception extends moodle_exception { 00076 function __construct($plugin, $pluginversion, $currentmoodle, $requiremoodle) { 00077 global $CFG; 00078 $a = new stdClass(); 00079 $a->pluginname = $plugin; 00080 $a->pluginversion = $pluginversion; 00081 $a->currentmoodle = $currentmoodle; 00082 $a->requiremoodle = $requiremoodle; 00083 parent::__construct('pluginrequirementsnotmet', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $a); 00084 } 00085 } 00086 00093 class plugin_defective_exception extends moodle_exception { 00094 function __construct($plugin, $details) { 00095 global $CFG; 00096 parent::__construct('detectedbrokenplugin', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $plugin, $details); 00097 } 00098 } 00099 00114 function upgrade_main_savepoint($result, $version, $allowabort=true) { 00115 global $CFG; 00116 00117 //sanity check to avoid confusion with upgrade_mod_savepoint usage. 00118 if (!is_bool($allowabort)) { 00119 $errormessage = 'Parameter type mismatch. Are you mixing up upgrade_main_savepoint() and upgrade_mod_savepoint()?'; 00120 throw new coding_exception($errormessage); 00121 } 00122 00123 if (!$result) { 00124 throw new upgrade_exception(null, $version); 00125 } 00126 00127 if ($CFG->version >= $version) { 00128 // something really wrong is going on in main upgrade script 00129 throw new downgrade_exception(null, $CFG->version, $version); 00130 } 00131 00132 set_config('version', $version); 00133 upgrade_log(UPGRADE_LOG_NORMAL, null, 'Upgrade savepoint reached'); 00134 00135 // reset upgrade timeout to default 00136 upgrade_set_timeout(); 00137 00138 // this is a safe place to stop upgrades if user aborts page loading 00139 if ($allowabort and connection_aborted()) { 00140 die; 00141 } 00142 } 00143 00156 function upgrade_mod_savepoint($result, $version, $modname, $allowabort=true) { 00157 global $DB; 00158 00159 if (!$result) { 00160 throw new upgrade_exception("mod_$modname", $version); 00161 } 00162 00163 if (!$module = $DB->get_record('modules', array('name'=>$modname))) { 00164 print_error('modulenotexist', 'debug', '', $modname); 00165 } 00166 00167 if ($module->version >= $version) { 00168 // something really wrong is going on in upgrade script 00169 throw new downgrade_exception("mod_$modname", $module->version, $version); 00170 } 00171 $module->version = $version; 00172 $DB->update_record('modules', $module); 00173 upgrade_log(UPGRADE_LOG_NORMAL, "mod_$modname", 'Upgrade savepoint reached'); 00174 00175 // reset upgrade timeout to default 00176 upgrade_set_timeout(); 00177 00178 // this is a safe place to stop upgrades if user aborts page loading 00179 if ($allowabort and connection_aborted()) { 00180 die; 00181 } 00182 } 00183 00196 function upgrade_block_savepoint($result, $version, $blockname, $allowabort=true) { 00197 global $DB; 00198 00199 if (!$result) { 00200 throw new upgrade_exception("block_$blockname", $version); 00201 } 00202 00203 if (!$block = $DB->get_record('block', array('name'=>$blockname))) { 00204 print_error('blocknotexist', 'debug', '', $blockname); 00205 } 00206 00207 if ($block->version >= $version) { 00208 // something really wrong is going on in upgrade script 00209 throw new downgrade_exception("block_$blockname", $block->version, $version); 00210 } 00211 $block->version = $version; 00212 $DB->update_record('block', $block); 00213 upgrade_log(UPGRADE_LOG_NORMAL, "block_$blockname", 'Upgrade savepoint reached'); 00214 00215 // reset upgrade timeout to default 00216 upgrade_set_timeout(); 00217 00218 // this is a safe place to stop upgrades if user aborts page loading 00219 if ($allowabort and connection_aborted()) { 00220 die; 00221 } 00222 } 00223 00236 function upgrade_plugin_savepoint($result, $version, $type, $plugin, $allowabort=true) { 00237 $component = $type.'_'.$plugin; 00238 00239 if (!$result) { 00240 throw new upgrade_exception($component, $version); 00241 } 00242 00243 $installedversion = get_config($component, 'version'); 00244 if ($installedversion >= $version) { 00245 // Something really wrong is going on in the upgrade script 00246 throw new downgrade_exception($component, $installedversion, $version); 00247 } 00248 set_config('version', $version, $component); 00249 upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached'); 00250 00251 // Reset upgrade timeout to default 00252 upgrade_set_timeout(); 00253 00254 // This is a safe place to stop upgrades if user aborts page loading 00255 if ($allowabort and connection_aborted()) { 00256 die; 00257 } 00258 } 00259 00260 00266 function upgrade_plugins($type, $startcallback, $endcallback, $verbose) { 00267 global $CFG, $DB; 00268 00270 if ($type === 'mod') { 00271 return upgrade_plugins_modules($startcallback, $endcallback, $verbose); 00272 } else if ($type === 'block') { 00273 return upgrade_plugins_blocks($startcallback, $endcallback, $verbose); 00274 } 00275 00276 $plugs = get_plugin_list($type); 00277 00278 foreach ($plugs as $plug=>$fullplug) { 00279 $component = clean_param($type.'_'.$plug, PARAM_COMPONENT); // standardised plugin name 00280 00281 // check plugin dir is valid name 00282 if (empty($component)) { 00283 throw new plugin_defective_exception($type.'_'.$plug, 'Invalid plugin directory name.'); 00284 } 00285 00286 if (!is_readable($fullplug.'/version.php')) { 00287 continue; 00288 } 00289 00290 $plugin = new stdClass(); 00291 require($fullplug.'/version.php'); // defines $plugin with version etc 00292 00293 // if plugin tells us it's full name we may check the location 00294 if (isset($plugin->component)) { 00295 if ($plugin->component !== $component) { 00296 throw new plugin_defective_exception($component, 'Plugin installed in wrong folder.'); 00297 } 00298 } 00299 00300 if (empty($plugin->version)) { 00301 throw new plugin_defective_exception($component, 'Missing version value in version.php'); 00302 } 00303 00304 $plugin->name = $plug; 00305 $plugin->fullname = $component; 00306 00307 00308 if (!empty($plugin->requires)) { 00309 if ($plugin->requires > $CFG->version) { 00310 throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires); 00311 } else if ($plugin->requires < 2010000000) { 00312 throw new plugin_defective_exception($component, 'Plugin is not compatible with Moodle 2.x or later.'); 00313 } 00314 } 00315 00316 // try to recover from interrupted install.php if needed 00317 if (file_exists($fullplug.'/db/install.php')) { 00318 if (get_config($plugin->fullname, 'installrunning')) { 00319 require_once($fullplug.'/db/install.php'); 00320 $recover_install_function = 'xmldb_'.$plugin->fullname.'_install_recovery'; 00321 if (function_exists($recover_install_function)) { 00322 $startcallback($component, true, $verbose); 00323 $recover_install_function(); 00324 unset_config('installrunning', $plugin->fullname); 00325 update_capabilities($component); 00326 log_update_descriptions($component); 00327 external_update_descriptions($component); 00328 events_update_definition($component); 00329 message_update_providers($component); 00330 if ($type === 'message') { 00331 message_update_processors($plug); 00332 } 00333 upgrade_plugin_mnet_functions($component); 00334 $endcallback($component, true, $verbose); 00335 } 00336 } 00337 } 00338 00339 $installedversion = get_config($plugin->fullname, 'version'); 00340 if (empty($installedversion)) { // new installation 00341 $startcallback($component, true, $verbose); 00342 00344 if (file_exists($fullplug.'/db/install.xml')) { 00345 $DB->get_manager()->install_from_xmldb_file($fullplug.'/db/install.xml'); 00346 } 00347 00349 upgrade_plugin_savepoint(true, $plugin->version, $type, $plug, false); 00350 00352 if (file_exists($fullplug.'/db/install.php')) { 00353 require_once($fullplug.'/db/install.php'); 00354 set_config('installrunning', 1, $plugin->fullname); 00355 $post_install_function = 'xmldb_'.$plugin->fullname.'_install'; 00356 $post_install_function(); 00357 unset_config('installrunning', $plugin->fullname); 00358 } 00359 00361 update_capabilities($component); 00362 log_update_descriptions($component); 00363 external_update_descriptions($component); 00364 events_update_definition($component); 00365 message_update_providers($component); 00366 if ($type === 'message') { 00367 message_update_processors($plug); 00368 } 00369 upgrade_plugin_mnet_functions($component); 00370 00371 purge_all_caches(); 00372 $endcallback($component, true, $verbose); 00373 00374 } else if ($installedversion < $plugin->version) { // upgrade 00376 $startcallback($component, false, $verbose); 00377 00378 if (is_readable($fullplug.'/db/upgrade.php')) { 00379 require_once($fullplug.'/db/upgrade.php'); // defines upgrading function 00380 00381 $newupgrade_function = 'xmldb_'.$plugin->fullname.'_upgrade'; 00382 $result = $newupgrade_function($installedversion); 00383 } else { 00384 $result = true; 00385 } 00386 00387 $installedversion = get_config($plugin->fullname, 'version'); 00388 if ($installedversion < $plugin->version) { 00389 // store version if not already there 00390 upgrade_plugin_savepoint($result, $plugin->version, $type, $plug, false); 00391 } 00392 00394 update_capabilities($component); 00395 log_update_descriptions($component); 00396 external_update_descriptions($component); 00397 events_update_definition($component); 00398 message_update_providers($component); 00399 if ($type === 'message') { 00400 message_update_processors($plug); 00401 } 00402 upgrade_plugin_mnet_functions($component); 00403 00404 purge_all_caches(); 00405 $endcallback($component, false, $verbose); 00406 00407 } else if ($installedversion > $plugin->version) { 00408 throw new downgrade_exception($component, $installedversion, $plugin->version); 00409 } 00410 } 00411 } 00412 00419 function upgrade_plugins_modules($startcallback, $endcallback, $verbose) { 00420 global $CFG, $DB; 00421 00422 $mods = get_plugin_list('mod'); 00423 00424 foreach ($mods as $mod=>$fullmod) { 00425 00426 if ($mod === 'NEWMODULE') { // Someone has unzipped the template, ignore it 00427 continue; 00428 } 00429 00430 $component = clean_param('mod_'.$mod, PARAM_COMPONENT); 00431 00432 // check module dir is valid name 00433 if (empty($component)) { 00434 throw new plugin_defective_exception('mod_'.$mod, 'Invalid plugin directory name.'); 00435 } 00436 00437 if (!is_readable($fullmod.'/version.php')) { 00438 throw new plugin_defective_exception($component, 'Missing version.php'); 00439 } 00440 00441 $module = new stdClass(); 00442 require($fullmod .'/version.php'); // defines $module with version etc 00443 00444 // if plugin tells us it's full name we may check the location 00445 if (isset($module->component)) { 00446 if ($module->component !== $component) { 00447 throw new plugin_defective_exception($component, 'Plugin installed in wrong folder.'); 00448 } 00449 } 00450 00451 if (empty($module->version)) { 00452 if (isset($module->version)) { 00453 // Version is empty but is set - it means its value is 0 or ''. Let us skip such module. 00454 // This is intended for developers so they can work on the early stages of the module. 00455 continue; 00456 } 00457 throw new plugin_defective_exception($component, 'Missing version value in version.php'); 00458 } 00459 00460 if (!empty($module->requires)) { 00461 if ($module->requires > $CFG->version) { 00462 throw new upgrade_requires_exception($component, $module->version, $CFG->version, $module->requires); 00463 } else if ($module->requires < 2010000000) { 00464 throw new plugin_defective_exception($component, 'Plugin is not compatible with Moodle 2.x or later.'); 00465 } 00466 } 00467 00468 if (empty($module->cron)) { 00469 $module->cron = 0; 00470 } 00471 00472 // all modules must have en lang pack 00473 if (!is_readable("$fullmod/lang/en/$mod.php")) { 00474 throw new plugin_defective_exception($component, 'Missing mandatory en language pack.'); 00475 } 00476 00477 $module->name = $mod; // The name MUST match the directory 00478 00479 $currmodule = $DB->get_record('modules', array('name'=>$module->name)); 00480 00481 if (file_exists($fullmod.'/db/install.php')) { 00482 if (get_config($module->name, 'installrunning')) { 00483 require_once($fullmod.'/db/install.php'); 00484 $recover_install_function = 'xmldb_'.$module->name.'_install_recovery'; 00485 if (function_exists($recover_install_function)) { 00486 $startcallback($component, true, $verbose); 00487 $recover_install_function(); 00488 unset_config('installrunning', $module->name); 00489 // Install various components too 00490 update_capabilities($component); 00491 log_update_descriptions($component); 00492 external_update_descriptions($component); 00493 events_update_definition($component); 00494 message_update_providers($component); 00495 upgrade_plugin_mnet_functions($component); 00496 $endcallback($component, true, $verbose); 00497 } 00498 } 00499 } 00500 00501 if (empty($currmodule->version)) { 00502 $startcallback($component, true, $verbose); 00503 00505 $DB->get_manager()->install_from_xmldb_file($fullmod.'/db/install.xml'); 00506 00508 $module->id = $DB->insert_record('modules', $module); 00509 00511 if (file_exists("$fullmod/db/install.php")) { 00512 require_once("$fullmod/db/install.php"); 00513 // Set installation running flag, we need to recover after exception or error 00514 set_config('installrunning', 1, $module->name); 00515 $post_install_function = 'xmldb_'.$module->name.'_install'; 00516 $post_install_function(); 00517 unset_config('installrunning', $module->name); 00518 } 00519 00521 update_capabilities($component); 00522 log_update_descriptions($component); 00523 external_update_descriptions($component); 00524 events_update_definition($component); 00525 message_update_providers($component); 00526 upgrade_plugin_mnet_functions($component); 00527 00528 purge_all_caches(); 00529 $endcallback($component, true, $verbose); 00530 00531 } else if ($currmodule->version < $module->version) { 00533 $startcallback($component, false, $verbose); 00534 00535 if (is_readable($fullmod.'/db/upgrade.php')) { 00536 require_once($fullmod.'/db/upgrade.php'); // defines new upgrading function 00537 $newupgrade_function = 'xmldb_'.$module->name.'_upgrade'; 00538 $result = $newupgrade_function($currmodule->version, $module); 00539 } else { 00540 $result = true; 00541 } 00542 00543 $currmodule = $DB->get_record('modules', array('name'=>$module->name)); 00544 if ($currmodule->version < $module->version) { 00545 // store version if not already there 00546 upgrade_mod_savepoint($result, $module->version, $mod, false); 00547 } 00548 00549 // update cron flag if needed 00550 if ($currmodule->cron != $module->cron) { 00551 $DB->set_field('modules', 'cron', $module->cron, array('name' => $module->name)); 00552 } 00553 00554 // Upgrade various components 00555 update_capabilities($component); 00556 log_update_descriptions($component); 00557 external_update_descriptions($component); 00558 events_update_definition($component); 00559 message_update_providers($component); 00560 upgrade_plugin_mnet_functions($component); 00561 00562 purge_all_caches(); 00563 00564 $endcallback($component, false, $verbose); 00565 00566 } else if ($currmodule->version > $module->version) { 00567 throw new downgrade_exception($component, $currmodule->version, $module->version); 00568 } 00569 } 00570 } 00571 00572 00580 function upgrade_plugins_blocks($startcallback, $endcallback, $verbose) { 00581 global $CFG, $DB; 00582 00583 require_once($CFG->dirroot.'/blocks/moodleblock.class.php'); 00584 00585 $blocktitles = array(); // we do not want duplicate titles 00586 00587 //Is this a first install 00588 $first_install = null; 00589 00590 $blocks = get_plugin_list('block'); 00591 00592 foreach ($blocks as $blockname=>$fullblock) { 00593 00594 if (is_null($first_install)) { 00595 $first_install = ($DB->count_records('block_instances') == 0); 00596 } 00597 00598 if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it 00599 continue; 00600 } 00601 00602 $component = clean_param('block_'.$blockname, PARAM_COMPONENT); 00603 00604 // check block dir is valid name 00605 if (empty($component)) { 00606 throw new plugin_defective_exception('block_'.$blockname, 'Invalid plugin directory name.'); 00607 } 00608 00609 if (!is_readable($fullblock.'/version.php')) { 00610 throw new plugin_defective_exception('block/'.$blockname, 'Missing version.php file.'); 00611 } 00612 $plugin = new stdClass(); 00613 $plugin->version = NULL; 00614 $plugin->cron = 0; 00615 include($fullblock.'/version.php'); 00616 $block = $plugin; 00617 00618 // if plugin tells us it's full name we may check the location 00619 if (isset($block->component)) { 00620 if ($block->component !== $component) { 00621 throw new plugin_defective_exception($component, 'Plugin installed in wrong folder.'); 00622 } 00623 } 00624 00625 if (!empty($plugin->requires)) { 00626 if ($plugin->requires > $CFG->version) { 00627 throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires); 00628 } else if ($plugin->requires < 2010000000) { 00629 throw new plugin_defective_exception($component, 'Plugin is not compatible with Moodle 2.x or later.'); 00630 } 00631 } 00632 00633 if (!is_readable($fullblock.'/block_'.$blockname.'.php')) { 00634 throw new plugin_defective_exception('block/'.$blockname, 'Missing main block class file.'); 00635 } 00636 include_once($fullblock.'/block_'.$blockname.'.php'); 00637 00638 $classname = 'block_'.$blockname; 00639 00640 if (!class_exists($classname)) { 00641 throw new plugin_defective_exception($component, 'Can not load main class.'); 00642 } 00643 00644 $blockobj = new $classname; // This is what we'll be testing 00645 $blocktitle = $blockobj->get_title(); 00646 00647 // OK, it's as we all hoped. For further tests, the object will do them itself. 00648 if (!$blockobj->_self_test()) { 00649 throw new plugin_defective_exception($component, 'Self test failed.'); 00650 } 00651 00652 $block->name = $blockname; // The name MUST match the directory 00653 00654 if (empty($block->version)) { 00655 throw new plugin_defective_exception($component, 'Missing block version.'); 00656 } 00657 00658 $currblock = $DB->get_record('block', array('name'=>$block->name)); 00659 00660 if (file_exists($fullblock.'/db/install.php')) { 00661 if (get_config('block_'.$blockname, 'installrunning')) { 00662 require_once($fullblock.'/db/install.php'); 00663 $recover_install_function = 'xmldb_block_'.$blockname.'_install_recovery'; 00664 if (function_exists($recover_install_function)) { 00665 $startcallback($component, true, $verbose); 00666 $recover_install_function(); 00667 unset_config('installrunning', 'block_'.$blockname); 00668 // Install various components 00669 update_capabilities($component); 00670 log_update_descriptions($component); 00671 external_update_descriptions($component); 00672 events_update_definition($component); 00673 message_update_providers($component); 00674 upgrade_plugin_mnet_functions($component); 00675 $endcallback($component, true, $verbose); 00676 } 00677 } 00678 } 00679 00680 if (empty($currblock->version)) { // block not installed yet, so install it 00681 $conflictblock = array_search($blocktitle, $blocktitles); 00682 if ($conflictblock !== false) { 00683 // Duplicate block titles are not allowed, they confuse people 00684 // AND PHP's associative arrays ;) 00685 throw new plugin_defective_exception($component, get_string('blocknameconflict', 'error', (object)array('name'=>$block->name, 'conflict'=>$conflictblock))); 00686 } 00687 $startcallback($component, true, $verbose); 00688 00689 if (file_exists($fullblock.'/db/install.xml')) { 00690 $DB->get_manager()->install_from_xmldb_file($fullblock.'/db/install.xml'); 00691 } 00692 $block->id = $DB->insert_record('block', $block); 00693 00694 if (file_exists($fullblock.'/db/install.php')) { 00695 require_once($fullblock.'/db/install.php'); 00696 // Set installation running flag, we need to recover after exception or error 00697 set_config('installrunning', 1, 'block_'.$blockname); 00698 $post_install_function = 'xmldb_block_'.$blockname.'_install';; 00699 $post_install_function(); 00700 unset_config('installrunning', 'block_'.$blockname); 00701 } 00702 00703 $blocktitles[$block->name] = $blocktitle; 00704 00705 // Install various components 00706 update_capabilities($component); 00707 log_update_descriptions($component); 00708 external_update_descriptions($component); 00709 events_update_definition($component); 00710 message_update_providers($component); 00711 upgrade_plugin_mnet_functions($component); 00712 00713 purge_all_caches(); 00714 $endcallback($component, true, $verbose); 00715 00716 } else if ($currblock->version < $block->version) { 00717 $startcallback($component, false, $verbose); 00718 00719 if (is_readable($fullblock.'/db/upgrade.php')) { 00720 require_once($fullblock.'/db/upgrade.php'); // defines new upgrading function 00721 $newupgrade_function = 'xmldb_block_'.$blockname.'_upgrade'; 00722 $result = $newupgrade_function($currblock->version, $block); 00723 } else { 00724 $result = true; 00725 } 00726 00727 $currblock = $DB->get_record('block', array('name'=>$block->name)); 00728 if ($currblock->version < $block->version) { 00729 // store version if not already there 00730 upgrade_block_savepoint($result, $block->version, $block->name, false); 00731 } 00732 00733 if ($currblock->cron != $block->cron) { 00734 // update cron flag if needed 00735 $currblock->cron = $block->cron; 00736 $DB->update_record('block', $currblock); 00737 } 00738 00739 // Upgrade various components 00740 update_capabilities($component); 00741 log_update_descriptions($component); 00742 external_update_descriptions($component); 00743 events_update_definition($component); 00744 message_update_providers($component); 00745 upgrade_plugin_mnet_functions($component); 00746 00747 purge_all_caches(); 00748 $endcallback($component, false, $verbose); 00749 00750 } else if ($currblock->version > $block->version) { 00751 throw new downgrade_exception($component, $currblock->version, $block->version); 00752 } 00753 } 00754 00755 00756 // Finally, if we are in the first_install of BLOCKS setup frontpage and admin page blocks 00757 if ($first_install) { 00758 //Iterate over each course - there should be only site course here now 00759 if ($courses = $DB->get_records('course')) { 00760 foreach ($courses as $course) { 00761 blocks_add_default_course_blocks($course); 00762 } 00763 } 00764 00765 blocks_add_default_system_blocks(); 00766 } 00767 } 00768 00769 00776 function log_update_descriptions($component) { 00777 global $DB; 00778 00779 $defpath = get_component_directory($component).'/db/log.php'; 00780 00781 if (!file_exists($defpath)) { 00782 $DB->delete_records('log_display', array('component'=>$component)); 00783 return; 00784 } 00785 00786 // load new info 00787 $logs = array(); 00788 include($defpath); 00789 $newlogs = array(); 00790 foreach ($logs as $log) { 00791 $newlogs[$log['module'].'-'.$log['action']] = $log; // kind of unique name 00792 } 00793 unset($logs); 00794 $logs = $newlogs; 00795 00796 $fields = array('module', 'action', 'mtable', 'field'); 00797 // update all log fist 00798 $dblogs = $DB->get_records('log_display', array('component'=>$component)); 00799 foreach ($dblogs as $dblog) { 00800 $name = $dblog->module.'-'.$dblog->action; 00801 00802 if (empty($logs[$name])) { 00803 $DB->delete_records('log_display', array('id'=>$dblog->id)); 00804 continue; 00805 } 00806 00807 $log = $logs[$name]; 00808 unset($logs[$name]); 00809 00810 $update = false; 00811 foreach ($fields as $field) { 00812 if ($dblog->$field != $log[$field]) { 00813 $dblog->$field = $log[$field]; 00814 $update = true; 00815 } 00816 } 00817 if ($update) { 00818 $DB->update_record('log_display', $dblog); 00819 } 00820 } 00821 foreach ($logs as $log) { 00822 $dblog = (object)$log; 00823 $dblog->component = $component; 00824 $DB->insert_record('log_display', $dblog); 00825 } 00826 } 00827 00833 function external_update_descriptions($component) { 00834 global $DB; 00835 00836 $defpath = get_component_directory($component).'/db/services.php'; 00837 00838 if (!file_exists($defpath)) { 00839 external_delete_descriptions($component); 00840 return; 00841 } 00842 00843 // load new info 00844 $functions = array(); 00845 $services = array(); 00846 include($defpath); 00847 00848 // update all function fist 00849 $dbfunctions = $DB->get_records('external_functions', array('component'=>$component)); 00850 foreach ($dbfunctions as $dbfunction) { 00851 if (empty($functions[$dbfunction->name])) { 00852 $DB->delete_records('external_functions', array('id'=>$dbfunction->id)); 00853 // do not delete functions from external_services_functions, beacuse 00854 // we want to notify admins when functions used in custom services disappear 00855 00856 //TODO: this looks wrong, we have to delete it eventually (skodak) 00857 continue; 00858 } 00859 00860 $function = $functions[$dbfunction->name]; 00861 unset($functions[$dbfunction->name]); 00862 $function['classpath'] = empty($function['classpath']) ? null : $function['classpath']; 00863 00864 $update = false; 00865 if ($dbfunction->classname != $function['classname']) { 00866 $dbfunction->classname = $function['classname']; 00867 $update = true; 00868 } 00869 if ($dbfunction->methodname != $function['methodname']) { 00870 $dbfunction->methodname = $function['methodname']; 00871 $update = true; 00872 } 00873 if ($dbfunction->classpath != $function['classpath']) { 00874 $dbfunction->classpath = $function['classpath']; 00875 $update = true; 00876 } 00877 $functioncapabilities = key_exists('capabilities', $function)?$function['capabilities']:''; 00878 if ($dbfunction->capabilities != $functioncapabilities) { 00879 $dbfunction->capabilities = $functioncapabilities; 00880 $update = true; 00881 } 00882 if ($update) { 00883 $DB->update_record('external_functions', $dbfunction); 00884 } 00885 } 00886 foreach ($functions as $fname => $function) { 00887 $dbfunction = new stdClass(); 00888 $dbfunction->name = $fname; 00889 $dbfunction->classname = $function['classname']; 00890 $dbfunction->methodname = $function['methodname']; 00891 $dbfunction->classpath = empty($function['classpath']) ? null : $function['classpath']; 00892 $dbfunction->component = $component; 00893 $dbfunction->capabilities = key_exists('capabilities', $function)?$function['capabilities']:''; 00894 $dbfunction->id = $DB->insert_record('external_functions', $dbfunction); 00895 } 00896 unset($functions); 00897 00898 // now deal with services 00899 $dbservices = $DB->get_records('external_services', array('component'=>$component)); 00900 foreach ($dbservices as $dbservice) { 00901 if (empty($services[$dbservice->name])) { 00902 $DB->delete_records('external_services_functions', array('externalserviceid'=>$dbservice->id)); 00903 $DB->delete_records('external_services_users', array('externalserviceid'=>$dbservice->id)); 00904 $DB->delete_records('external_services', array('id'=>$dbservice->id)); 00905 continue; 00906 } 00907 $service = $services[$dbservice->name]; 00908 unset($services[$dbservice->name]); 00909 $service['enabled'] = empty($service['enabled']) ? 0 : $service['enabled']; 00910 $service['requiredcapability'] = empty($service['requiredcapability']) ? null : $service['requiredcapability']; 00911 $service['restrictedusers'] = !isset($service['restrictedusers']) ? 1 : $service['restrictedusers']; 00912 $service['downloadfiles'] = !isset($service['downloadfiles']) ? 0 : $service['downloadfiles']; 00913 $service['shortname'] = !isset($service['shortname']) ? null : $service['shortname']; 00914 00915 $update = false; 00916 if ($dbservice->requiredcapability != $service['requiredcapability']) { 00917 $dbservice->requiredcapability = $service['requiredcapability']; 00918 $update = true; 00919 } 00920 if ($dbservice->restrictedusers != $service['restrictedusers']) { 00921 $dbservice->restrictedusers = $service['restrictedusers']; 00922 $update = true; 00923 } 00924 if ($dbservice->downloadfiles != $service['downloadfiles']) { 00925 $dbservice->downloadfiles = $service['downloadfiles']; 00926 $update = true; 00927 } 00928 //if shortname is not a PARAM_ALPHANUMEXT, fail (tested here for service update and creation) 00929 if (isset($service['shortname']) and 00930 (clean_param($service['shortname'], PARAM_ALPHANUMEXT) != $service['shortname'])) { 00931 throw new moodle_exception('installserviceshortnameerror', 'webservice', '', $service['shortname']); 00932 } 00933 if ($dbservice->shortname != $service['shortname']) { 00934 //check that shortname is unique 00935 if (isset($service['shortname'])) { //we currently accepts multiple shortname == null 00936 $existingservice = $DB->get_record('external_services', 00937 array('shortname' => $service['shortname'])); 00938 if (!empty($existingservice)) { 00939 throw new moodle_exception('installexistingserviceshortnameerror', 'webservice', '', $service['shortname']); 00940 } 00941 } 00942 $dbservice->shortname = $service['shortname']; 00943 $update = true; 00944 } 00945 if ($update) { 00946 $DB->update_record('external_services', $dbservice); 00947 } 00948 00949 $functions = $DB->get_records('external_services_functions', array('externalserviceid'=>$dbservice->id)); 00950 foreach ($functions as $function) { 00951 $key = array_search($function->functionname, $service['functions']); 00952 if ($key === false) { 00953 $DB->delete_records('external_services_functions', array('id'=>$function->id)); 00954 } else { 00955 unset($service['functions'][$key]); 00956 } 00957 } 00958 foreach ($service['functions'] as $fname) { 00959 $newf = new stdClass(); 00960 $newf->externalserviceid = $dbservice->id; 00961 $newf->functionname = $fname; 00962 $DB->insert_record('external_services_functions', $newf); 00963 } 00964 unset($functions); 00965 } 00966 foreach ($services as $name => $service) { 00967 //check that shortname is unique 00968 if (isset($service['shortname'])) { //we currently accepts multiple shortname == null 00969 $existingservice = $DB->get_record('external_services', 00970 array('shortname' => $service['shortname'])); 00971 if (!empty($existingservice)) { 00972 throw new moodle_exception('installserviceshortnameerror', 'webservice'); 00973 } 00974 } 00975 00976 $dbservice = new stdClass(); 00977 $dbservice->name = $name; 00978 $dbservice->enabled = empty($service['enabled']) ? 0 : $service['enabled']; 00979 $dbservice->requiredcapability = empty($service['requiredcapability']) ? null : $service['requiredcapability']; 00980 $dbservice->restrictedusers = !isset($service['restrictedusers']) ? 1 : $service['restrictedusers']; 00981 $dbservice->downloadfiles = !isset($service['downloadfiles']) ? 0 : $service['downloadfiles']; 00982 $dbservice->shortname = !isset($service['shortname']) ? null : $service['shortname']; 00983 $dbservice->component = $component; 00984 $dbservice->timecreated = time(); 00985 $dbservice->id = $DB->insert_record('external_services', $dbservice); 00986 foreach ($service['functions'] as $fname) { 00987 $newf = new stdClass(); 00988 $newf->externalserviceid = $dbservice->id; 00989 $newf->functionname = $fname; 00990 $DB->insert_record('external_services_functions', $newf); 00991 } 00992 } 00993 } 00994 01000 function external_delete_descriptions($component) { 01001 global $DB; 01002 01003 $params = array($component); 01004 01005 $DB->delete_records_select('external_services_users', "externalserviceid IN (SELECT id FROM {external_services} WHERE component = ?)", $params); 01006 $DB->delete_records_select('external_services_functions', "externalserviceid IN (SELECT id FROM {external_services} WHERE component = ?)", $params); 01007 $DB->delete_records('external_services', array('component'=>$component)); 01008 $DB->delete_records('external_functions', array('component'=>$component)); 01009 } 01010 01014 function upgrade_handle_exception($ex, $plugin = null) { 01015 global $CFG; 01016 01017 // rollback everything, we need to log all upgrade problems 01018 abort_all_db_transactions(); 01019 01020 $info = get_exception_info($ex); 01021 01022 // First log upgrade error 01023 upgrade_log(UPGRADE_LOG_ERROR, $plugin, 'Exception: ' . get_class($ex), $info->message, $info->backtrace); 01024 01025 // Always turn on debugging - admins need to know what is going on 01026 $CFG->debug = DEBUG_DEVELOPER; 01027 01028 default_exception_handler($ex, true, $plugin); 01029 } 01030 01041 function upgrade_log($type, $plugin, $info, $details=null, $backtrace=null) { 01042 global $DB, $USER, $CFG; 01043 01044 if (empty($plugin)) { 01045 $plugin = 'core'; 01046 } 01047 01048 list($plugintype, $pluginname) = normalize_component($plugin); 01049 $component = is_null($pluginname) ? $plugintype : $plugintype . '_' . $pluginname; 01050 01051 $backtrace = format_backtrace($backtrace, true); 01052 01053 $currentversion = null; 01054 $targetversion = null; 01055 01056 //first try to find out current version number 01057 if ($plugintype === 'core') { 01058 //main 01059 $currentversion = $CFG->version; 01060 01061 $version = null; 01062 include("$CFG->dirroot/version.php"); 01063 $targetversion = $version; 01064 01065 } else if ($plugintype === 'mod') { 01066 try { 01067 $currentversion = $DB->get_field('modules', 'version', array('name'=>$pluginname)); 01068 $currentversion = ($currentversion === false) ? null : $currentversion; 01069 } catch (Exception $ignored) { 01070 } 01071 $cd = get_component_directory($component); 01072 if (file_exists("$cd/version.php")) { 01073 $module = new stdClass(); 01074 $module->version = null; 01075 include("$cd/version.php"); 01076 $targetversion = $module->version; 01077 } 01078 01079 } else if ($plugintype === 'block') { 01080 try { 01081 if ($block = $DB->get_record('block', array('name'=>$pluginname))) { 01082 $currentversion = $block->version; 01083 } 01084 } catch (Exception $ignored) { 01085 } 01086 $cd = get_component_directory($component); 01087 if (file_exists("$cd/version.php")) { 01088 $plugin = new stdClass(); 01089 $plugin->version = null; 01090 include("$cd/version.php"); 01091 $targetversion = $plugin->version; 01092 } 01093 01094 } else { 01095 $pluginversion = get_config($component, 'version'); 01096 if (!empty($pluginversion)) { 01097 $currentversion = $pluginversion; 01098 } 01099 $cd = get_component_directory($component); 01100 if (file_exists("$cd/version.php")) { 01101 $plugin = new stdClass(); 01102 $plugin->version = null; 01103 include("$cd/version.php"); 01104 $targetversion = $plugin->version; 01105 } 01106 } 01107 01108 $log = new stdClass(); 01109 $log->type = $type; 01110 $log->plugin = $component; 01111 $log->version = $currentversion; 01112 $log->targetversion = $targetversion; 01113 $log->info = $info; 01114 $log->details = $details; 01115 $log->backtrace = $backtrace; 01116 $log->userid = $USER->id; 01117 $log->timemodified = time(); 01118 try { 01119 $DB->insert_record('upgrade_log', $log); 01120 } catch (Exception $ignored) { 01121 // possible during install or 2.0 upgrade 01122 } 01123 } 01124 01133 function upgrade_started($preinstall=false) { 01134 global $CFG, $DB, $PAGE, $OUTPUT; 01135 01136 static $started = false; 01137 01138 if ($preinstall) { 01139 ignore_user_abort(true); 01140 upgrade_setup_debug(true); 01141 01142 } else if ($started) { 01143 upgrade_set_timeout(120); 01144 01145 } else { 01146 if (!CLI_SCRIPT and !$PAGE->headerprinted) { 01147 $strupgrade = get_string('upgradingversion', 'admin'); 01148 $PAGE->set_pagelayout('maintenance'); 01149 upgrade_init_javascript(); 01150 $PAGE->set_title($strupgrade.' - Moodle '.$CFG->target_release); 01151 $PAGE->set_heading($strupgrade); 01152 $PAGE->navbar->add($strupgrade); 01153 $PAGE->set_cacheable(false); 01154 echo $OUTPUT->header(); 01155 } 01156 01157 ignore_user_abort(true); 01158 register_shutdown_function('upgrade_finished_handler'); 01159 upgrade_setup_debug(true); 01160 set_config('upgraderunning', time()+300); 01161 $started = true; 01162 } 01163 } 01164 01168 function upgrade_finished_handler() { 01169 upgrade_finished(); 01170 } 01171 01180 function upgrade_finished($continueurl=null) { 01181 global $CFG, $DB, $OUTPUT; 01182 01183 if (!empty($CFG->upgraderunning)) { 01184 unset_config('upgraderunning'); 01185 upgrade_setup_debug(false); 01186 ignore_user_abort(false); 01187 if ($continueurl) { 01188 echo $OUTPUT->continue_button($continueurl); 01189 echo $OUTPUT->footer(); 01190 die; 01191 } 01192 } 01193 } 01194 01199 function upgrade_setup_debug($starting) { 01200 global $CFG, $DB; 01201 01202 static $originaldebug = null; 01203 01204 if ($starting) { 01205 if ($originaldebug === null) { 01206 $originaldebug = $DB->get_debug(); 01207 } 01208 if (!empty($CFG->upgradeshowsql)) { 01209 $DB->set_debug(true); 01210 } 01211 } else { 01212 $DB->set_debug($originaldebug); 01213 } 01214 } 01215 01216 function print_upgrade_separator() { 01217 if (!CLI_SCRIPT) { 01218 echo '<hr />'; 01219 } 01220 } 01221 01227 function print_upgrade_part_start($plugin, $installation, $verbose) { 01228 global $OUTPUT; 01229 if (empty($plugin) or $plugin == 'moodle') { 01230 upgrade_started($installation); // does not store upgrade running flag yet 01231 if ($verbose) { 01232 echo $OUTPUT->heading(get_string('coresystem')); 01233 } 01234 } else { 01235 upgrade_started(); 01236 if ($verbose) { 01237 echo $OUTPUT->heading($plugin); 01238 } 01239 } 01240 if ($installation) { 01241 if (empty($plugin) or $plugin == 'moodle') { 01242 // no need to log - log table not yet there ;-) 01243 } else { 01244 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin installation'); 01245 } 01246 } else { 01247 if (empty($plugin) or $plugin == 'moodle') { 01248 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting core upgrade'); 01249 } else { 01250 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Starting plugin upgrade'); 01251 } 01252 } 01253 } 01254 01260 function print_upgrade_part_end($plugin, $installation, $verbose) { 01261 global $OUTPUT; 01262 upgrade_started(); 01263 if ($installation) { 01264 if (empty($plugin) or $plugin == 'moodle') { 01265 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core installed'); 01266 } else { 01267 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin installed'); 01268 } 01269 } else { 01270 if (empty($plugin) or $plugin == 'moodle') { 01271 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Core upgraded'); 01272 } else { 01273 upgrade_log(UPGRADE_LOG_NORMAL, $plugin, 'Plugin upgraded'); 01274 } 01275 } 01276 if ($verbose) { 01277 echo $OUTPUT->notification(get_string('success'), 'notifysuccess'); 01278 print_upgrade_separator(); 01279 } 01280 } 01281 01286 function upgrade_init_javascript() { 01287 global $PAGE; 01288 // scroll to the end of each upgrade page so that ppl see either error or continue button, 01289 // no need to scroll continuously any more, it is enough to jump to end once the footer is printed ;-) 01290 $js = "window.scrollTo(0, 5000000);"; 01291 $PAGE->requires->js_init_code($js); 01292 } 01293 01299 function upgrade_language_pack($lang = null) { 01300 global $CFG; 01301 01302 if (!empty($CFG->skiplangupgrade)) { 01303 return; 01304 } 01305 01306 if (!file_exists("$CFG->dirroot/$CFG->admin/tool/langimport/lib.php")) { 01307 // weird, somebody uninstalled the import utility 01308 return; 01309 } 01310 01311 if (!$lang) { 01312 $lang = current_language(); 01313 } 01314 01315 if (!get_string_manager()->translation_exists($lang)) { 01316 return; 01317 } 01318 01319 get_string_manager()->reset_caches(); 01320 01321 if ($lang === 'en') { 01322 return; // Nothing to do 01323 } 01324 01325 upgrade_started(false); 01326 01327 require_once("$CFG->dirroot/$CFG->admin/tool/langimport/lib.php"); 01328 tool_langimport_preupgrade_update($lang); 01329 01330 get_string_manager()->reset_caches(); 01331 01332 print_upgrade_separator(); 01333 } 01334 01341 function install_core($version, $verbose) { 01342 global $CFG, $DB; 01343 01344 try { 01345 set_time_limit(600); 01346 print_upgrade_part_start('moodle', true, $verbose); // does not store upgrade running flag 01347 01348 $DB->get_manager()->install_from_xmldb_file("$CFG->libdir/db/install.xml"); 01349 upgrade_started(); // we want the flag to be stored in config table ;-) 01350 01351 // set all core default records and default settings 01352 require_once("$CFG->libdir/db/install.php"); 01353 xmldb_main_install(); // installs the capabilities too 01354 01355 // store version 01356 upgrade_main_savepoint(true, $version, false); 01357 01358 // Continue with the installation 01359 log_update_descriptions('moodle'); 01360 external_update_descriptions('moodle'); 01361 events_update_definition('moodle'); 01362 message_update_providers('moodle'); 01363 01364 // Write default settings unconditionally 01365 admin_apply_default_settings(NULL, true); 01366 01367 print_upgrade_part_end(null, true, $verbose); 01368 } catch (exception $ex) { 01369 upgrade_handle_exception($ex); 01370 } 01371 } 01372 01379 function upgrade_core($version, $verbose) { 01380 global $CFG; 01381 01382 raise_memory_limit(MEMORY_EXTRA); 01383 01384 require_once($CFG->libdir.'/db/upgrade.php'); // Defines upgrades 01385 01386 try { 01387 // Reset caches before any output 01388 purge_all_caches(); 01389 01390 // Upgrade current language pack if we can 01391 upgrade_language_pack(); 01392 01393 print_upgrade_part_start('moodle', false, $verbose); 01394 01395 // one time special local migration pre 2.0 upgrade script 01396 if ($CFG->version < 2007101600) { 01397 $pre20upgradefile = "$CFG->dirroot/local/upgrade_pre20.php"; 01398 if (file_exists($pre20upgradefile)) { 01399 set_time_limit(0); 01400 require($pre20upgradefile); 01401 // reset upgrade timeout to default 01402 upgrade_set_timeout(); 01403 } 01404 } 01405 01406 $result = xmldb_main_upgrade($CFG->version); 01407 if ($version > $CFG->version) { 01408 // store version if not already there 01409 upgrade_main_savepoint($result, $version, false); 01410 } 01411 01412 // perform all other component upgrade routines 01413 update_capabilities('moodle'); 01414 log_update_descriptions('moodle'); 01415 external_update_descriptions('moodle'); 01416 events_update_definition('moodle'); 01417 message_update_providers('moodle'); 01418 01419 // Reset caches again, just to be sure 01420 purge_all_caches(); 01421 01422 // Clean up contexts - more and more stuff depends on existence of paths and contexts 01423 context_helper::cleanup_instances(); 01424 context_helper::create_instances(null, false); 01425 context_helper::build_all_paths(false); 01426 $syscontext = context_system::instance(); 01427 $syscontext->mark_dirty(); 01428 01429 print_upgrade_part_end('moodle', false, $verbose); 01430 } catch (Exception $ex) { 01431 upgrade_handle_exception($ex); 01432 } 01433 } 01434 01440 function upgrade_noncore($verbose) { 01441 global $CFG; 01442 01443 raise_memory_limit(MEMORY_EXTRA); 01444 01445 // upgrade all plugins types 01446 try { 01447 $plugintypes = get_plugin_types(); 01448 foreach ($plugintypes as $type=>$location) { 01449 upgrade_plugins($type, 'print_upgrade_part_start', 'print_upgrade_part_end', $verbose); 01450 } 01451 } catch (Exception $ex) { 01452 upgrade_handle_exception($ex); 01453 } 01454 } 01455 01460 function core_tables_exist() { 01461 global $DB; 01462 01463 if (!$tables = $DB->get_tables() ) { // No tables yet at all. 01464 return false; 01465 01466 } else { // Check for missing main tables 01467 $mtables = array('config', 'course', 'groupings'); // some tables used in 1.9 and 2.0, preferable something from the start and end of install.xml 01468 foreach ($mtables as $mtable) { 01469 if (!in_array($mtable, $tables)) { 01470 return false; 01471 } 01472 } 01473 return true; 01474 } 01475 } 01476 01483 function upgrade_plugin_mnet_functions($component) { 01484 global $DB, $CFG; 01485 01486 list($type, $plugin) = explode('_', $component); 01487 $path = get_plugin_directory($type, $plugin); 01488 01489 $publishes = array(); 01490 $subscribes = array(); 01491 if (file_exists($path . '/db/mnet.php')) { 01492 require_once($path . '/db/mnet.php'); // $publishes comes from this file 01493 } 01494 if (empty($publishes)) { 01495 $publishes = array(); // still need this to be able to disable stuff later 01496 } 01497 if (empty($subscribes)) { 01498 $subscribes = array(); // still need this to be able to disable stuff later 01499 } 01500 01501 static $servicecache = array(); 01502 01503 // rekey an array based on the rpc method for easy lookups later 01504 $publishmethodservices = array(); 01505 $subscribemethodservices = array(); 01506 foreach($publishes as $servicename => $service) { 01507 if (is_array($service['methods'])) { 01508 foreach($service['methods'] as $methodname) { 01509 $service['servicename'] = $servicename; 01510 $publishmethodservices[$methodname][] = $service; 01511 } 01512 } 01513 } 01514 01515 // Disable functions that don't exist (any more) in the source 01516 // Should these be deleted? What about their permissions records? 01517 foreach ($DB->get_records('mnet_rpc', array('pluginname'=>$plugin, 'plugintype'=>$type), 'functionname ASC ') as $rpc) { 01518 if (!array_key_exists($rpc->functionname, $publishmethodservices) && $rpc->enabled) { 01519 $DB->set_field('mnet_rpc', 'enabled', 0, array('id' => $rpc->id)); 01520 } else if (array_key_exists($rpc->functionname, $publishmethodservices) && !$rpc->enabled) { 01521 $DB->set_field('mnet_rpc', 'enabled', 1, array('id' => $rpc->id)); 01522 } 01523 } 01524 01525 // reflect all the services we're publishing and save them 01526 require_once($CFG->dirroot . '/lib/zend/Zend/Server/Reflection.php'); 01527 static $cachedclasses = array(); // to store reflection information in 01528 foreach ($publishes as $service => $data) { 01529 $f = $data['filename']; 01530 $c = $data['classname']; 01531 foreach ($data['methods'] as $method) { 01532 $dataobject = new stdClass(); 01533 $dataobject->plugintype = $type; 01534 $dataobject->pluginname = $plugin; 01535 $dataobject->enabled = 1; 01536 $dataobject->classname = $c; 01537 $dataobject->filename = $f; 01538 01539 if (is_string($method)) { 01540 $dataobject->functionname = $method; 01541 01542 } else if (is_array($method)) { // wants to override file or class 01543 $dataobject->functionname = $method['method']; 01544 $dataobject->classname = $method['classname']; 01545 $dataobject->filename = $method['filename']; 01546 } 01547 $dataobject->xmlrpcpath = $type.'/'.$plugin.'/'.$dataobject->filename.'/'.$method; 01548 $dataobject->static = false; 01549 01550 require_once($path . '/' . $dataobject->filename); 01551 $functionreflect = null; // slightly different ways to get this depending on whether it's a class method or a function 01552 if (!empty($dataobject->classname)) { 01553 if (!class_exists($dataobject->classname)) { 01554 throw new moodle_exception('installnosuchmethod', 'mnet', '', (object)array('method' => $dataobject->functionname, 'class' => $dataobject->classname)); 01555 } 01556 $key = $dataobject->filename . '|' . $dataobject->classname; 01557 if (!array_key_exists($key, $cachedclasses)) { // look to see if we've already got a reflection object 01558 try { 01559 $cachedclasses[$key] = Zend_Server_Reflection::reflectClass($dataobject->classname); 01560 } catch (Zend_Server_Reflection_Exception $e) { // catch these and rethrow them to something more helpful 01561 throw new moodle_exception('installreflectionclasserror', 'mnet', '', (object)array('method' => $dataobject->functionname, 'class' => $dataobject->classname, 'error' => $e->getMessage())); 01562 } 01563 } 01564 $r =& $cachedclasses[$key]; 01565 if (!$r->hasMethod($dataobject->functionname)) { 01566 throw new moodle_exception('installnosuchmethod', 'mnet', '', (object)array('method' => $dataobject->functionname, 'class' => $dataobject->classname)); 01567 } 01568 // stupid workaround for zend not having a getMethod($name) function 01569 $ms = $r->getMethods(); 01570 foreach ($ms as $m) { 01571 if ($m->getName() == $dataobject->functionname) { 01572 $functionreflect = $m; 01573 break; 01574 } 01575 } 01576 $dataobject->static = (int)$functionreflect->isStatic(); 01577 } else { 01578 if (!function_exists($dataobject->functionname)) { 01579 throw new moodle_exception('installnosuchfunction', 'mnet', '', (object)array('method' => $dataobject->functionname, 'file' => $dataobject->filename)); 01580 } 01581 try { 01582 $functionreflect = Zend_Server_Reflection::reflectFunction($dataobject->functionname); 01583 } catch (Zend_Server_Reflection_Exception $e) { // catch these and rethrow them to something more helpful 01584 throw new moodle_exception('installreflectionfunctionerror', 'mnet', '', (object)array('method' => $dataobject->functionname, '' => $dataobject->filename, 'error' => $e->getMessage())); 01585 } 01586 } 01587 $dataobject->profile = serialize(admin_mnet_method_profile($functionreflect)); 01588 $dataobject->help = $functionreflect->getDescription(); 01589 01590 if ($record_exists = $DB->get_record('mnet_rpc', array('xmlrpcpath'=>$dataobject->xmlrpcpath))) { 01591 $dataobject->id = $record_exists->id; 01592 $dataobject->enabled = $record_exists->enabled; 01593 $DB->update_record('mnet_rpc', $dataobject); 01594 } else { 01595 $dataobject->id = $DB->insert_record('mnet_rpc', $dataobject, true); 01596 } 01597 01598 // TODO this API versioning must be reworked, here the recently processed method 01599 // sets the service API which may not be correct 01600 foreach ($publishmethodservices[$dataobject->functionname] as $service) { 01601 if ($serviceobj = $DB->get_record('mnet_service', array('name'=>$service['servicename']))) { 01602 $serviceobj->apiversion = $service['apiversion']; 01603 $DB->update_record('mnet_service', $serviceobj); 01604 } else { 01605 $serviceobj = new stdClass(); 01606 $serviceobj->name = $service['servicename']; 01607 $serviceobj->description = empty($service['description']) ? '' : $service['description']; 01608 $serviceobj->apiversion = $service['apiversion']; 01609 $serviceobj->offer = 1; 01610 $serviceobj->id = $DB->insert_record('mnet_service', $serviceobj); 01611 } 01612 $servicecache[$service['servicename']] = $serviceobj; 01613 if (!$DB->record_exists('mnet_service2rpc', array('rpcid'=>$dataobject->id, 'serviceid'=>$serviceobj->id))) { 01614 $obj = new stdClass(); 01615 $obj->rpcid = $dataobject->id; 01616 $obj->serviceid = $serviceobj->id; 01617 $DB->insert_record('mnet_service2rpc', $obj, true); 01618 } 01619 } 01620 } 01621 } 01622 // finished with methods we publish, now do subscribable methods 01623 foreach($subscribes as $service => $methods) { 01624 if (!array_key_exists($service, $servicecache)) { 01625 if (!$serviceobj = $DB->get_record('mnet_service', array('name' => $service))) { 01626 debugging("TODO: skipping unknown service $service - somebody needs to fix MDL-21993"); 01627 continue; 01628 } 01629 $servicecache[$service] = $serviceobj; 01630 } else { 01631 $serviceobj = $servicecache[$service]; 01632 } 01633 foreach ($methods as $method => $xmlrpcpath) { 01634 if (!$rpcid = $DB->get_field('mnet_remote_rpc', 'id', array('xmlrpcpath'=>$xmlrpcpath))) { 01635 $remoterpc = (object)array( 01636 'functionname' => $method, 01637 'xmlrpcpath' => $xmlrpcpath, 01638 'plugintype' => $type, 01639 'pluginname' => $plugin, 01640 'enabled' => 1, 01641 ); 01642 $rpcid = $remoterpc->id = $DB->insert_record('mnet_remote_rpc', $remoterpc, true); 01643 } 01644 if (!$DB->record_exists('mnet_remote_service2rpc', array('rpcid'=>$rpcid, 'serviceid'=>$serviceobj->id))) { 01645 $obj = new stdClass(); 01646 $obj->rpcid = $rpcid; 01647 $obj->serviceid = $serviceobj->id; 01648 $DB->insert_record('mnet_remote_service2rpc', $obj, true); 01649 } 01650 $subscribemethodservices[$method][] = $service; 01651 } 01652 } 01653 01654 foreach ($DB->get_records('mnet_remote_rpc', array('pluginname'=>$plugin, 'plugintype'=>$type), 'functionname ASC ') as $rpc) { 01655 if (!array_key_exists($rpc->functionname, $subscribemethodservices) && $rpc->enabled) { 01656 $DB->set_field('mnet_remote_rpc', 'enabled', 0, array('id' => $rpc->id)); 01657 } else if (array_key_exists($rpc->functionname, $subscribemethodservices) && !$rpc->enabled) { 01658 $DB->set_field('mnet_remote_rpc', 'enabled', 1, array('id' => $rpc->id)); 01659 } 01660 } 01661 01662 return true; 01663 } 01664 01672 function admin_mnet_method_profile(Zend_Server_Reflection_Function_Abstract $function) { 01673 $proto = array_pop($function->getPrototypes()); 01674 $ret = $proto->getReturnValue(); 01675 $profile = array( 01676 'parameters' => array(), 01677 'return' => array( 01678 'type' => $ret->getType(), 01679 'description' => $ret->getDescription(), 01680 ), 01681 ); 01682 foreach ($proto->getParameters() as $p) { 01683 $profile['parameters'][] = array( 01684 'name' => $p->getName(), 01685 'type' => $p->getType(), 01686 'description' => $p->getDescription(), 01687 ); 01688 } 01689 return $profile; 01690 }