/lib/upgradelib.php
PHP | 2613 lines | 1681 code | 348 blank | 584 comment | 319 complexity | 9ab291a387223604640c78f5335cb890 MD5 | raw file
Possible License(s): MIT, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, Apache-2.0, LGPL-2.1, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- <?php
- // This file is part of Moodle - http://moodle.org/
- //
- // Moodle is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // Moodle is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
- /**
- * Various upgrade/install related functions and classes.
- *
- * @package core
- * @subpackage upgrade
- * @copyright 1999 onwards Martin Dougiamas (http://dougiamas.com)
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- defined('MOODLE_INTERNAL') || die();
- /** UPGRADE_LOG_NORMAL = 0 */
- define('UPGRADE_LOG_NORMAL', 0);
- /** UPGRADE_LOG_NOTICE = 1 */
- define('UPGRADE_LOG_NOTICE', 1);
- /** UPGRADE_LOG_ERROR = 2 */
- define('UPGRADE_LOG_ERROR', 2);
- /**
- * Exception indicating unknown error during upgrade.
- *
- * @package core
- * @subpackage upgrade
- * @copyright 2009 Petr Skoda {@link http://skodak.org}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- class upgrade_exception extends moodle_exception {
- function __construct($plugin, $version, $debuginfo=NULL) {
- global $CFG;
- $a = (object)array('plugin'=>$plugin, 'version'=>$version);
- parent::__construct('upgradeerror', 'admin', "$CFG->wwwroot/$CFG->admin/index.php", $a, $debuginfo);
- }
- }
- /**
- * Exception indicating downgrade error during upgrade.
- *
- * @package core
- * @subpackage upgrade
- * @copyright 2009 Petr Skoda {@link http://skodak.org}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- class downgrade_exception extends moodle_exception {
- function __construct($plugin, $oldversion, $newversion) {
- global $CFG;
- $plugin = is_null($plugin) ? 'moodle' : $plugin;
- $a = (object)array('plugin'=>$plugin, 'oldversion'=>$oldversion, 'newversion'=>$newversion);
- parent::__construct('cannotdowngrade', 'debug', "$CFG->wwwroot/$CFG->admin/index.php", $a);
- }
- }
- /**
- * @package core
- * @subpackage upgrade
- * @copyright 2009 Petr Skoda {@link http://skodak.org}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- class upgrade_requires_exception extends moodle_exception {
- function __construct($plugin, $pluginversion, $currentmoodle, $requiremoodle) {
- global $CFG;
- $a = new stdClass();
- $a->pluginname = $plugin;
- $a->pluginversion = $pluginversion;
- $a->currentmoodle = $currentmoodle;
- $a->requiremoodle = $requiremoodle;
- parent::__construct('pluginrequirementsnotmet', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $a);
- }
- }
- /**
- * Exception thrown when attempting to install a plugin that declares incompatibility with moodle version
- *
- * @package core
- * @subpackage upgrade
- * @copyright 2019 Peter Burnett <peterburnett@catalyst-au.net>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- class plugin_incompatible_exception extends moodle_exception {
- /**
- * Constructor function for exception
- *
- * @param \core\plugininfo\base $plugin The plugin causing the exception
- * @param int $pluginversion The version of the plugin causing the exception
- */
- public function __construct($plugin, $pluginversion) {
- global $CFG;
- $a = new stdClass();
- $a->pluginname = $plugin;
- $a->pluginversion = $pluginversion;
- $a->moodleversion = $CFG->branch;
- parent::__construct('pluginunsupported', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $a);
- }
- }
- /**
- * @package core
- * @subpackage upgrade
- * @copyright 2009 Petr Skoda {@link http://skodak.org}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- class plugin_defective_exception extends moodle_exception {
- function __construct($plugin, $details) {
- global $CFG;
- parent::__construct('detectedbrokenplugin', 'error', "$CFG->wwwroot/$CFG->admin/index.php", $plugin, $details);
- }
- }
- /**
- * Misplaced plugin exception.
- *
- * Note: this should be used only from the upgrade/admin code.
- *
- * @package core
- * @subpackage upgrade
- * @copyright 2009 Petr Skoda {@link http://skodak.org}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
- class plugin_misplaced_exception extends moodle_exception {
- /**
- * Constructor.
- * @param string $component the component from version.php
- * @param string $expected expected directory, null means calculate
- * @param string $current plugin directory path
- */
- public function __construct($component, $expected, $current) {
- global $CFG;
- if (empty($expected)) {
- list($type, $plugin) = core_component::normalize_component($component);
- $plugintypes = core_component::get_plugin_types();
- if (isset($plugintypes[$type])) {
- $expected = $plugintypes[$type] . '/' . $plugin;
- }
- }
- if (strpos($expected, '$CFG->dirroot') !== 0) {
- $expected = str_replace($CFG->dirroot, '$CFG->dirroot', $expected);
- }
- if (strpos($current, '$CFG->dirroot') !== 0) {
- $current = str_replace($CFG->dirroot, '$CFG->dirroot', $current);
- }
- $a = new stdClass();
- $a->component = $component;
- $a->expected = $expected;
- $a->current = $current;
- parent::__construct('detectedmisplacedplugin', 'core_plugin', "$CFG->wwwroot/$CFG->admin/index.php", $a);
- }
- }
- /**
- * Static class monitors performance of upgrade steps.
- */
- class core_upgrade_time {
- /** @var float Time at start of current upgrade (plugin/system) */
- protected static $before;
- /** @var float Time at end of last savepoint */
- protected static $lastsavepoint;
- /** @var bool Flag to indicate whether we are recording timestamps or not. */
- protected static $isrecording = false;
- /**
- * Records current time at the start of the current upgrade item, e.g. plugin.
- */
- public static function record_start() {
- self::$before = microtime(true);
- self::$lastsavepoint = self::$before;
- self::$isrecording = true;
- }
- /**
- * Records current time at the end of a given numbered step.
- *
- * @param float $version Version number (may have decimals, or not)
- */
- public static function record_savepoint($version) {
- global $CFG, $OUTPUT;
- // In developer debug mode we show a notification after each individual save point.
- if ($CFG->debugdeveloper && self::$isrecording) {
- $time = microtime(true);
- $notification = new \core\output\notification($version . ': ' .
- get_string('successduration', '', format_float($time - self::$lastsavepoint, 2)),
- \core\output\notification::NOTIFY_SUCCESS);
- $notification->set_show_closebutton(false);
- echo $OUTPUT->render($notification);
- self::$lastsavepoint = $time;
- }
- }
- /**
- * Gets the time since the record_start function was called, rounded to 2 digits.
- *
- * @return float Elapsed time
- */
- public static function get_elapsed() {
- return microtime(true) - self::$before;
- }
- }
- /**
- * Sets maximum expected time needed for upgrade task.
- * Please always make sure that upgrade will not run longer!
- *
- * The script may be automatically aborted if upgrade times out.
- *
- * @category upgrade
- * @param int $max_execution_time in seconds (can not be less than 60 s)
- */
- function upgrade_set_timeout($max_execution_time=300) {
- global $CFG;
- if (!isset($CFG->upgraderunning) or $CFG->upgraderunning < time()) {
- $upgraderunning = get_config(null, 'upgraderunning');
- } else {
- $upgraderunning = $CFG->upgraderunning;
- }
- if (!$upgraderunning) {
- if (CLI_SCRIPT) {
- // never stop CLI upgrades
- $upgraderunning = 0;
- } else {
- // web upgrade not running or aborted
- print_error('upgradetimedout', 'admin', "$CFG->wwwroot/$CFG->admin/");
- }
- }
- if ($max_execution_time < 60) {
- // protection against 0 here
- $max_execution_time = 60;
- }
- $expected_end = time() + $max_execution_time;
- if ($expected_end < $upgraderunning + 10 and $expected_end > $upgraderunning - 10) {
- // no need to store new end, it is nearly the same ;-)
- return;
- }
- if (CLI_SCRIPT) {
- // there is no point in timing out of CLI scripts, admins can stop them if necessary
- core_php_time_limit::raise();
- } else {
- core_php_time_limit::raise($max_execution_time);
- }
- set_config('upgraderunning', $expected_end); // keep upgrade locked until this time
- }
- /**
- * Upgrade savepoint, marks end of each upgrade block.
- * It stores new main version, resets upgrade timeout
- * and abort upgrade if user cancels page loading.
- *
- * Please do not make large upgrade blocks with lots of operations,
- * for example when adding tables keep only one table operation per block.
- *
- * @category upgrade
- * @param bool $result false if upgrade step failed, true if completed
- * @param string or float $version main version
- * @param bool $allowabort allow user to abort script execution here
- * @return void
- */
- function upgrade_main_savepoint($result, $version, $allowabort=true) {
- global $CFG;
- //sanity check to avoid confusion with upgrade_mod_savepoint usage.
- if (!is_bool($allowabort)) {
- $errormessage = 'Parameter type mismatch. Are you mixing up upgrade_main_savepoint() and upgrade_mod_savepoint()?';
- throw new coding_exception($errormessage);
- }
- if (!$result) {
- throw new upgrade_exception(null, $version);
- }
- if ($CFG->version >= $version) {
- // something really wrong is going on in main upgrade script
- throw new downgrade_exception(null, $CFG->version, $version);
- }
- set_config('version', $version);
- upgrade_log(UPGRADE_LOG_NORMAL, null, 'Upgrade savepoint reached');
- // reset upgrade timeout to default
- upgrade_set_timeout();
- core_upgrade_time::record_savepoint($version);
- // this is a safe place to stop upgrades if user aborts page loading
- if ($allowabort and connection_aborted()) {
- die;
- }
- }
- /**
- * Module upgrade savepoint, marks end of module upgrade blocks
- * It stores module version, resets upgrade timeout
- * and abort upgrade if user cancels page loading.
- *
- * @category upgrade
- * @param bool $result false if upgrade step failed, true if completed
- * @param string or float $version main version
- * @param string $modname name of module
- * @param bool $allowabort allow user to abort script execution here
- * @return void
- */
- function upgrade_mod_savepoint($result, $version, $modname, $allowabort=true) {
- global $DB;
- $component = 'mod_'.$modname;
- if (!$result) {
- throw new upgrade_exception($component, $version);
- }
- $dbversion = $DB->get_field('config_plugins', 'value', array('plugin'=>$component, 'name'=>'version'));
- if (!$module = $DB->get_record('modules', array('name'=>$modname))) {
- print_error('modulenotexist', 'debug', '', $modname);
- }
- if ($dbversion >= $version) {
- // something really wrong is going on in upgrade script
- throw new downgrade_exception($component, $dbversion, $version);
- }
- set_config('version', $version, $component);
- upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached');
- // reset upgrade timeout to default
- upgrade_set_timeout();
- core_upgrade_time::record_savepoint($version);
- // this is a safe place to stop upgrades if user aborts page loading
- if ($allowabort and connection_aborted()) {
- die;
- }
- }
- /**
- * Blocks upgrade savepoint, marks end of blocks upgrade blocks
- * It stores block version, resets upgrade timeout
- * and abort upgrade if user cancels page loading.
- *
- * @category upgrade
- * @param bool $result false if upgrade step failed, true if completed
- * @param string or float $version main version
- * @param string $blockname name of block
- * @param bool $allowabort allow user to abort script execution here
- * @return void
- */
- function upgrade_block_savepoint($result, $version, $blockname, $allowabort=true) {
- global $DB;
- $component = 'block_'.$blockname;
- if (!$result) {
- throw new upgrade_exception($component, $version);
- }
- $dbversion = $DB->get_field('config_plugins', 'value', array('plugin'=>$component, 'name'=>'version'));
- if (!$block = $DB->get_record('block', array('name'=>$blockname))) {
- print_error('blocknotexist', 'debug', '', $blockname);
- }
- if ($dbversion >= $version) {
- // something really wrong is going on in upgrade script
- throw new downgrade_exception($component, $dbversion, $version);
- }
- set_config('version', $version, $component);
- upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached');
- // reset upgrade timeout to default
- upgrade_set_timeout();
- core_upgrade_time::record_savepoint($version);
- // this is a safe place to stop upgrades if user aborts page loading
- if ($allowabort and connection_aborted()) {
- die;
- }
- }
- /**
- * Plugins upgrade savepoint, marks end of blocks upgrade blocks
- * It stores plugin version, resets upgrade timeout
- * and abort upgrade if user cancels page loading.
- *
- * @category upgrade
- * @param bool $result false if upgrade step failed, true if completed
- * @param string or float $version main version
- * @param string $type The type of the plugin.
- * @param string $plugin The name of the plugin.
- * @param bool $allowabort allow user to abort script execution here
- * @return void
- */
- function upgrade_plugin_savepoint($result, $version, $type, $plugin, $allowabort=true) {
- global $DB;
- $component = $type.'_'.$plugin;
- if (!$result) {
- throw new upgrade_exception($component, $version);
- }
- $dbversion = $DB->get_field('config_plugins', 'value', array('plugin'=>$component, 'name'=>'version'));
- if ($dbversion >= $version) {
- // Something really wrong is going on in the upgrade script
- throw new downgrade_exception($component, $dbversion, $version);
- }
- set_config('version', $version, $component);
- upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached');
- // Reset upgrade timeout to default
- upgrade_set_timeout();
- core_upgrade_time::record_savepoint($version);
- // This is a safe place to stop upgrades if user aborts page loading
- if ($allowabort and connection_aborted()) {
- die;
- }
- }
- /**
- * Detect if there are leftovers in PHP source files.
- *
- * During main version upgrades administrators MUST move away
- * old PHP source files and start from scratch (or better
- * use git).
- *
- * @return bool true means borked upgrade, false means previous PHP files were properly removed
- */
- function upgrade_stale_php_files_present() {
- global $CFG;
- $someexamplesofremovedfiles = array(
- // Removed in 3.9.
- '/course/classes/output/modchooser_item.php',
- '/course/yui/build/moodle-course-modchooser/moodle-course-modchooser-min.js',
- '/course/yui/src/modchooser/js/modchooser.js',
- '/h5p/classes/autoloader.php',
- '/lib/adodb/readme.txt',
- '/lib/maxmind/GeoIp2/Compat/JsonSerializable.php',
- // Removed in 3.8.
- '/lib/amd/src/modal_confirm.js',
- '/lib/fonts/font-awesome-4.7.0/css/font-awesome.css',
- '/lib/jquery/jquery-3.2.1.min.js',
- '/lib/recaptchalib.php',
- '/lib/sessionkeepalive_ajax.php',
- '/lib/yui/src/checknet/js/checknet.js',
- '/question/amd/src/qbankmanager.js',
- // Removed in 3.7.
- '/lib/form/yui/src/showadvanced/js/showadvanced.js',
- '/lib/tests/output_external_test.php',
- '/message/amd/src/message_area.js',
- '/message/templates/message_area.mustache',
- '/question/yui/src/qbankmanager/build.json',
- // Removed in 3.6.
- '/lib/classes/session/memcache.php',
- '/lib/eventslib.php',
- '/lib/form/submitlink.php',
- '/lib/medialib.php',
- '/lib/password_compat/lib/password.php',
- // Removed in 3.5.
- '/lib/dml/mssql_native_moodle_database.php',
- '/lib/dml/mssql_native_moodle_recordset.php',
- '/lib/dml/mssql_native_moodle_temptables.php',
- // Removed in 3.4.
- '/auth/README.txt',
- '/calendar/set.php',
- '/enrol/users.php',
- '/enrol/yui/rolemanager/assets/skins/sam/rolemanager.css',
- // Removed in 3.3.
- '/badges/backpackconnect.php',
- '/calendar/yui/src/info/assets/skins/sam/moodle-calendar-info.css',
- '/competency/classes/external/exporter.php',
- '/mod/forum/forum.js',
- '/user/pixgroup.php',
- // Removed in 3.2.
- '/calendar/preferences.php',
- '/lib/alfresco/',
- '/lib/jquery/jquery-1.12.1.min.js',
- '/lib/password_compat/tests/',
- '/lib/phpunit/classes/unittestcase.php',
- // Removed in 3.1.
- '/lib/classes/log/sql_internal_reader.php',
- '/lib/zend/',
- '/mod/forum/pix/icon.gif',
- '/tag/templates/tagname.mustache',
- // Removed in 3.0.
- '/mod/lti/grade.php',
- '/tag/coursetagslib.php',
- // Removed in 2.9.
- '/lib/timezone.txt',
- // Removed in 2.8.
- '/course/delete_category_form.php',
- // Removed in 2.7.
- '/admin/tool/qeupgradehelper/version.php',
- // Removed in 2.6.
- '/admin/block.php',
- '/admin/oacleanup.php',
- // Removed in 2.5.
- '/backup/lib.php',
- '/backup/bb/README.txt',
- '/lib/excel/test.php',
- // Removed in 2.4.
- '/admin/tool/unittest/simpletestlib.php',
- // Removed in 2.3.
- '/lib/minify/builder/',
- // Removed in 2.2.
- '/lib/yui/3.4.1pr1/',
- // Removed in 2.2.
- '/search/cron_php5.php',
- '/course/report/log/indexlive.php',
- '/admin/report/backups/index.php',
- '/admin/generator.php',
- // Removed in 2.1.
- '/lib/yui/2.8.0r4/',
- // Removed in 2.0.
- '/blocks/admin/block_admin.php',
- '/blocks/admin_tree/block_admin_tree.php',
- );
- foreach ($someexamplesofremovedfiles as $file) {
- if (file_exists($CFG->dirroot.$file)) {
- return true;
- }
- }
- return false;
- }
- /**
- * Upgrade plugins
- * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
- * return void
- */
- function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
- global $CFG, $DB;
- /// special cases
- if ($type === 'mod') {
- return upgrade_plugins_modules($startcallback, $endcallback, $verbose);
- } else if ($type === 'block') {
- return upgrade_plugins_blocks($startcallback, $endcallback, $verbose);
- }
- $plugs = core_component::get_plugin_list($type);
- foreach ($plugs as $plug=>$fullplug) {
- // Reset time so that it works when installing a large number of plugins
- core_php_time_limit::raise(600);
- $component = clean_param($type.'_'.$plug, PARAM_COMPONENT); // standardised plugin name
- // check plugin dir is valid name
- if (empty($component)) {
- throw new plugin_defective_exception($type.'_'.$plug, 'Invalid plugin directory name.');
- }
- if (!is_readable($fullplug.'/version.php')) {
- continue;
- }
- $plugin = new stdClass();
- $plugin->version = null;
- $module = $plugin; // Prevent some notices when plugin placed in wrong directory.
- require($fullplug.'/version.php'); // defines $plugin with version etc
- unset($module);
- if (empty($plugin->version)) {
- throw new plugin_defective_exception($component, 'Missing $plugin->version number in version.php.');
- }
- if (empty($plugin->component)) {
- throw new plugin_defective_exception($component, 'Missing $plugin->component declaration in version.php.');
- }
- if ($plugin->component !== $component) {
- throw new plugin_misplaced_exception($plugin->component, null, $fullplug);
- }
- $plugin->name = $plug;
- $plugin->fullname = $component;
- if (!empty($plugin->requires)) {
- if ($plugin->requires > $CFG->version) {
- throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires);
- } else if ($plugin->requires < 2010000000) {
- throw new plugin_defective_exception($component, 'Plugin is not compatible with Moodle 2.x or later.');
- }
- }
- // Throw exception if plugin is incompatible with moodle version.
- if (!empty($plugin->incompatible)) {
- if ($CFG->branch <= $plugin->incompatible) {
- throw new plugin_incompatible_exception($component, $plugin->version);
- }
- }
- // try to recover from interrupted install.php if needed
- if (file_exists($fullplug.'/db/install.php')) {
- if (get_config($plugin->fullname, 'installrunning')) {
- require_once($fullplug.'/db/install.php');
- $recover_install_function = 'xmldb_'.$plugin->fullname.'_install_recovery';
- if (function_exists($recover_install_function)) {
- $startcallback($component, true, $verbose);
- $recover_install_function();
- unset_config('installrunning', $plugin->fullname);
- update_capabilities($component);
- log_update_descriptions($component);
- external_update_descriptions($component);
- \core\task\manager::reset_scheduled_tasks_for_component($component);
- \core_analytics\manager::update_default_models_for_component($component);
- message_update_providers($component);
- \core\message\inbound\manager::update_handlers_for_component($component);
- if ($type === 'message') {
- message_update_processors($plug);
- }
- upgrade_plugin_mnet_functions($component);
- core_tag_area::reset_definitions_for_component($component);
- $endcallback($component, true, $verbose);
- }
- }
- }
- $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching!
- if (empty($installedversion)) { // new installation
- $startcallback($component, true, $verbose);
- /// Install tables if defined
- if (file_exists($fullplug.'/db/install.xml')) {
- $DB->get_manager()->install_from_xmldb_file($fullplug.'/db/install.xml');
- }
- /// store version
- upgrade_plugin_savepoint(true, $plugin->version, $type, $plug, false);
- /// execute post install file
- if (file_exists($fullplug.'/db/install.php')) {
- require_once($fullplug.'/db/install.php');
- set_config('installrunning', 1, $plugin->fullname);
- $post_install_function = 'xmldb_'.$plugin->fullname.'_install';
- $post_install_function();
- unset_config('installrunning', $plugin->fullname);
- }
- /// Install various components
- update_capabilities($component);
- log_update_descriptions($component);
- external_update_descriptions($component);
- \core\task\manager::reset_scheduled_tasks_for_component($component);
- \core_analytics\manager::update_default_models_for_component($component);
- message_update_providers($component);
- \core\message\inbound\manager::update_handlers_for_component($component);
- if ($type === 'message') {
- message_update_processors($plug);
- }
- upgrade_plugin_mnet_functions($component);
- core_tag_area::reset_definitions_for_component($component);
- $endcallback($component, true, $verbose);
- } else if ($installedversion < $plugin->version) { // upgrade
- /// Run the upgrade function for the plugin.
- $startcallback($component, false, $verbose);
- if (is_readable($fullplug.'/db/upgrade.php')) {
- require_once($fullplug.'/db/upgrade.php'); // defines upgrading function
- $newupgrade_function = 'xmldb_'.$plugin->fullname.'_upgrade';
- $result = $newupgrade_function($installedversion);
- } else {
- $result = true;
- }
- $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching!
- if ($installedversion < $plugin->version) {
- // store version if not already there
- upgrade_plugin_savepoint($result, $plugin->version, $type, $plug, false);
- }
- /// Upgrade various components
- update_capabilities($component);
- log_update_descriptions($component);
- external_update_descriptions($component);
- \core\task\manager::reset_scheduled_tasks_for_component($component);
- \core_analytics\manager::update_default_models_for_component($component);
- message_update_providers($component);
- \core\message\inbound\manager::update_handlers_for_component($component);
- if ($type === 'message') {
- // Ugly hack!
- message_update_processors($plug);
- }
- upgrade_plugin_mnet_functions($component);
- core_tag_area::reset_definitions_for_component($component);
- $endcallback($component, false, $verbose);
- } else if ($installedversion > $plugin->version) {
- throw new downgrade_exception($component, $installedversion, $plugin->version);
- }
- }
- }
- /**
- * Find and check all modules and load them up or upgrade them if necessary
- *
- * @global object
- * @global object
- */
- function upgrade_plugins_modules($startcallback, $endcallback, $verbose) {
- global $CFG, $DB;
- $mods = core_component::get_plugin_list('mod');
- foreach ($mods as $mod=>$fullmod) {
- if ($mod === 'NEWMODULE') { // Someone has unzipped the template, ignore it
- continue;
- }
- $component = clean_param('mod_'.$mod, PARAM_COMPONENT);
- // check module dir is valid name
- if (empty($component)) {
- throw new plugin_defective_exception('mod_'.$mod, 'Invalid plugin directory name.');
- }
- if (!is_readable($fullmod.'/version.php')) {
- throw new plugin_defective_exception($component, 'Missing version.php');
- }
- $module = new stdClass();
- $plugin = new stdClass();
- $plugin->version = null;
- require($fullmod .'/version.php'); // Defines $plugin with version etc.
- // Check if the legacy $module syntax is still used.
- if (!is_object($module) or (count((array)$module) > 0)) {
- throw new plugin_defective_exception($component, 'Unsupported $module syntax detected in version.php');
- }
- // Prepare the record for the {modules} table.
- $module = clone($plugin);
- unset($module->version);
- unset($module->component);
- unset($module->dependencies);
- unset($module->release);
- if (empty($plugin->version)) {
- throw new plugin_defective_exception($component, 'Missing $plugin->version number in version.php.');
- }
- if (empty($plugin->component)) {
- throw new plugin_defective_exception($component, 'Missing $plugin->component declaration in version.php.');
- }
- if ($plugin->component !== $component) {
- throw new plugin_misplaced_exception($plugin->component, null, $fullmod);
- }
- if (!empty($plugin->requires)) {
- if ($plugin->requires > $CFG->version) {
- throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires);
- } else if ($plugin->requires < 2010000000) {
- throw new plugin_defective_exception($component, 'Plugin is not compatible with Moodle 2.x or later.');
- }
- }
- if (empty($module->cron)) {
- $module->cron = 0;
- }
- // all modules must have en lang pack
- if (!is_readable("$fullmod/lang/en/$mod.php")) {
- throw new plugin_defective_exception($component, 'Missing mandatory en language pack.');
- }
- $module->name = $mod; // The name MUST match the directory
- $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching!
- if (file_exists($fullmod.'/db/install.php')) {
- if (get_config($module->name, 'installrunning')) {
- require_once($fullmod.'/db/install.php');
- $recover_install_function = 'xmldb_'.$module->name.'_install_recovery';
- if (function_exists($recover_install_function)) {
- $startcallback($component, true, $verbose);
- $recover_install_function();
- unset_config('installrunning', $module->name);
- // Install various components too
- update_capabilities($component);
- log_update_descriptions($component);
- external_update_descriptions($component);
- \core\task\manager::reset_scheduled_tasks_for_component($component);
- \core_analytics\manager::update_default_models_for_component($component);
- message_update_providers($component);
- \core\message\inbound\manager::update_handlers_for_component($component);
- upgrade_plugin_mnet_functions($component);
- core_tag_area::reset_definitions_for_component($component);
- $endcallback($component, true, $verbose);
- }
- }
- }
- if (empty($installedversion)) {
- $startcallback($component, true, $verbose);
- /// Execute install.xml (XMLDB) - must be present in all modules
- $DB->get_manager()->install_from_xmldb_file($fullmod.'/db/install.xml');
- /// Add record into modules table - may be needed in install.php already
- $module->id = $DB->insert_record('modules', $module);
- upgrade_mod_savepoint(true, $plugin->version, $module->name, false);
- /// Post installation hook - optional
- if (file_exists("$fullmod/db/install.php")) {
- require_once("$fullmod/db/install.php");
- // Set installation running flag, we need to recover after exception or error
- set_config('installrunning', 1, $module->name);
- $post_install_function = 'xmldb_'.$module->name.'_install';
- $post_install_function();
- unset_config('installrunning', $module->name);
- }
- /// Install various components
- update_capabilities($component);
- log_update_descriptions($component);
- external_update_descriptions($component);
- \core\task\manager::reset_scheduled_tasks_for_component($component);
- \core_analytics\manager::update_default_models_for_component($component);
- message_update_providers($component);
- \core\message\inbound\manager::update_handlers_for_component($component);
- upgrade_plugin_mnet_functions($component);
- core_tag_area::reset_definitions_for_component($component);
- $endcallback($component, true, $verbose);
- } else if ($installedversion < $plugin->version) {
- /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
- $startcallback($component, false, $verbose);
- if (is_readable($fullmod.'/db/upgrade.php')) {
- require_once($fullmod.'/db/upgrade.php'); // defines new upgrading function
- $newupgrade_function = 'xmldb_'.$module->name.'_upgrade';
- $result = $newupgrade_function($installedversion, $module);
- } else {
- $result = true;
- }
- $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching!
- $currmodule = $DB->get_record('modules', array('name'=>$module->name));
- if ($installedversion < $plugin->version) {
- // store version if not already there
- upgrade_mod_savepoint($result, $plugin->version, $mod, false);
- }
- // update cron flag if needed
- if ($currmodule->cron != $module->cron) {
- $DB->set_field('modules', 'cron', $module->cron, array('name' => $module->name));
- }
- // Upgrade various components
- update_capabilities($component);
- log_update_descriptions($component);
- external_update_descriptions($component);
- \core\task\manager::reset_scheduled_tasks_for_component($component);
- \core_analytics\manager::update_default_models_for_component($component);
- message_update_providers($component);
- \core\message\inbound\manager::update_handlers_for_component($component);
- upgrade_plugin_mnet_functions($component);
- core_tag_area::reset_definitions_for_component($component);
- $endcallback($component, false, $verbose);
- } else if ($installedversion > $plugin->version) {
- throw new downgrade_exception($component, $installedversion, $plugin->version);
- }
- }
- }
- /**
- * This function finds all available blocks and install them
- * into blocks table or do all the upgrade process if newer.
- *
- * @global object
- * @global object
- */
- function upgrade_plugins_blocks($startcallback, $endcallback, $verbose) {
- global $CFG, $DB;
- require_once($CFG->dirroot.'/blocks/moodleblock.class.php');
- $blocktitles = array(); // we do not want duplicate titles
- //Is this a first install
- $first_install = null;
- $blocks = core_component::get_plugin_list('block');
- foreach ($blocks as $blockname=>$fullblock) {
- if (is_null($first_install)) {
- $first_install = ($DB->count_records('block_instances') == 0);
- }
- if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it
- continue;
- }
- $component = clean_param('block_'.$blockname, PARAM_COMPONENT);
- // check block dir is valid name
- if (empty($component)) {
- throw new plugin_defective_exception('block_'.$blockname, 'Invalid plugin directory name.');
- }
- if (!is_readable($fullblock.'/version.php')) {
- throw new plugin_defective_exception('block/'.$blockname, 'Missing version.php file.');
- }
- $plugin = new stdClass();
- $plugin->version = null;
- $plugin->cron = 0;
- $module = $plugin; // Prevent some notices when module placed in wrong directory.
- include($fullblock.'/version.php');
- unset($module);
- $block = clone($plugin);
- unset($block->version);
- unset($block->component);
- unset($block->dependencies);
- unset($block->release);
- if (empty($plugin->version)) {
- throw new plugin_defective_exception($component, 'Missing block version number in version.php.');
- }
- if (empty($plugin->component)) {
- throw new plugin_defective_exception($component, 'Missing $plugin->component declaration in version.php.');
- }
- if ($plugin->component !== $component) {
- throw new plugin_misplaced_exception($plugin->component, null, $fullblock);
- }
- if (!empty($plugin->requires)) {
- if ($plugin->requires > $CFG->version) {
- throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires);
- } else if ($plugin->requires < 2010000000) {
- throw new plugin_defective_exception($component, 'Plugin is not compatible with Moodle 2.x or later.');
- }
- }
- if (!is_readable($fullblock.'/block_'.$blockname.'.php')) {
- throw new plugin_defective_exception('block/'.$blockname, 'Missing main block class file.');
- }
- include_once($fullblock.'/block_'.$blockname.'.php');
- $classname = 'block_'.$blockname;
- if (!class_exists($classname)) {
- throw new plugin_defective_exception($component, 'Can not load main class.');
- }
- $blockobj = new $classname; // This is what we'll be testing
- $blocktitle = $blockobj->get_title();
- // OK, it's as we all hoped. For further tests, the object will do them itself.
- if (!$blockobj->_self_test()) {
- throw new plugin_defective_exception($component, 'Self test failed.');
- }
- $block->name = $blockname; // The name MUST match the directory
- $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching!
- if (file_exists($fullblock.'/db/install.php')) {
- if (get_config('block_'.$blockname, 'installrunning')) {
- require_once($fullblock.'/db/install.php');
- $recover_install_function = 'xmldb_block_'.$blockname.'_install_recovery';
- if (function_exists($recover_install_function)) {
- $startcallback($component, true, $verbose);
- $recover_install_function();
- unset_config('installrunning', 'block_'.$blockname);
- // Install various components
- update_capabilities($component);
- log_update_descriptions($component);
- external_update_descriptions($component);
- \core\task\manager::reset_scheduled_tasks_for_component($component);
- \core_analytics\manager::update_default_models_for_component($component);
- message_update_providers($component);
- \core\message\inbound\manager::update_handlers_for_component($component);
- upgrade_plugin_mnet_functions($component);
- core_tag_area::reset_definitions_for_component($component);
- $endcallback($component, true, $verbose);
- }
- }
- }
- if (empty($installedversion)) { // block not installed yet, so install it
- $conflictblock = array_search($blocktitle, $blocktitles);
- if ($conflictblock !== false) {
- // Duplicate block titles are not allowed, they confuse people
- // AND PHP's associative arrays ;)
- throw new plugin_defective_exception($component, get_string('blocknameconflict', 'error', (object)array('name'=>$block->name, 'conflict'=>$conflictblock)));
- }
- $startcallback($component, true, $verbose);
- if (file_exists($fullblock.'/db/install.xml')) {
- $DB->get_manager()->install_from_xmldb_file($fullblock.'/db/install.xml');
- }
- $block->id = $DB->insert_record('block', $block);
- upgrade_block_savepoint(true, $plugin->version, $block->name, false);
- if (file_exists($fullblock.'/db/install.php')) {
- require_once($fullblock.'/db/install.php');
- // Set installation running flag, we need to recover after exception or error
- set_config('installrunning', 1, 'block_'.$blockname);
- $post_install_function = 'xmldb_block_'.$blockname.'_install';
- $post_install_function();
- unset_config('installrunning', 'block_'.$blockname);
- }
- $blocktitles[$block->name] = $blocktitle;
- // Install various components
- update_capabilities($component);
- log_update_descriptions($component);
- external_update_descriptions($component);
- \core\task\manager::reset_scheduled_tasks_for_component($component);
- \core_analytics\manager::update_default_models_for_component($component);
- message_update_providers($component);
- \core\message\inbound\manager::update_handlers_for_component($component);
- core_tag_area::reset_definitions_for_component($component);
- upgrade_plugin_mnet_functions($component);
- $endcallback($component, true, $verbose);
- } else if ($installedversion < $plugin->version) {
- $startcallback($component, false, $verbose);
- if (is_readable($fullblock.'/db/upgrade.php')) {
- require_once($fullblock.'/db/upgrade.php'); // defines new upgrading function
- $newupgrade_function = 'xmldb_block_'.$blockname.'_upgrade';
- $result = $newupgrade_function($installedversion, $block);
- } else {
- $result = true;
- }
- $installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching!
- $currblock = $DB->get_record('block', array('name'=>$block->name));
- if ($installedversion < $plugin->version) {
- // store version if not already there
- upgrade_block_savepoint($result, $plugin->version, $block->name, false);
- }
- if ($currblock->cron != $block->cron) {
- // update cron flag if needed
- $DB->set_field('block', 'cron', $block->cron, array('id' => $currblock->id));
- }
- // Upgrade various components
- update_capabilities($component);
- log_update_descriptions($component);
- external_update_descriptions($component);
- \core\task\manager::reset_scheduled_tasks_for_component($component);
- \core_analytics\manager::update_default_models_for_component($component);
- message_update_providers($component);
- \core\message\inbound\manager::update_handlers_for_component($component);
- upgrade_plugin_mnet_functions($component);
- core_tag_area::reset_definitions_for_component($component);
- $endcallback($component, false, $verbose);
- } else if ($installedversion > $plugin->version) {
- throw new downgrade_exception($component, $installedversion, $plugin->version);
- }
- }
- // Finally, if we are in the first_install of BLOCKS setup frontpage and admin page blocks
- if ($first_install) {
- //Iterate over each course - there should be only site course here now
- if ($courses = $DB->get_records('course')) {
- foreach ($courses as $course) {
- blocks_add_default_course_blocks($course);
- }
- }
- blocks_add_default_system_blocks();
- }
- }
- /**
- * Log_display description function used during install and upgrade.
- *
- * @param string $component name of component (moodle, mod_assignment, etc.)
- * @return void
- */
- function log_update_descriptions($component) {
- global $DB;
- $defpath = core_component::get_component_directory($component).'/db/log.php';
- if (!file_exists($defpath)) {
- $DB->delete_records('log_display', array('component'=>$component));
- return;
- }
- // load new info
- $logs = array();
- include($defpath);
- $newlogs = array();
- foreach ($logs as $log) {
- $newlogs[$log['module'].'-'.$log['action']] = $log; // kind of unique name
- }
- unset($logs);
- $logs = $newlogs;
- $fields = array('module', 'action', 'mtable', 'field');
- // update all log fist
- $dblogs = $DB->get_records('log_display', array('component'=>$component));
- foreach ($dblogs as $dblog) {
- $name = $dblog->module.'-'.$dblog->action;
- if (empty($logs[$name])) {
- $DB->delete_records('log_display', array('id'=>$dblog->id));
- continue;
- }
- $log = $logs[$name];
- unset($logs[$name]);
- $update = false;
- foreach ($fields as $field) {
- if ($dblog->$field != $log[$field]) {
- $dblog->$field = $log[$field];
- $update = true;
- }
- }
- if ($update) {
- $DB->update_record('log_display', $dblog);
- }
- }
- foreach ($logs as $log) {
- $dblog = (object)$log;
- $dblog->component = $component;
- $DB->insert_record('log_display', $dblog);
- }
- }
- /**
- * Web service discovery function used during install and upgrade.
- * @param string $component name of component (moodle, mod_assignment, etc.)
- * @return void
- */
- function external_update_descriptions($component) {
- global $DB, $CFG;
- $defpath = core_component::get_component_directory($component).'/db/services.php';
- if (!file_exists($defpath)) {
- require_once($CFG->dirroot.'/lib/externallib.php');
- external_delete_descriptions($component);
- return;
- }
- // load new info
- $functions = array();
- $services = array();
- include($defpath);
- // update all function fist
- $dbfunctions = $DB->get_records('external_functions', array('component'=>$component));
- foreach ($dbfunctions as $dbfunction) {
- if (empty($functions[$dbfunction->name])) {
- $DB->delete_records('external_functions', array('id'=>$dbfunction->id));
- // do not delete functions from external_services_functions, beacuse
- // we want to notify admins when functions used in custom services disappear
- //TODO: this looks wrong, we have to delete it eventually (skodak)
- continue;
- }
- $function = $functions[$dbfunction->name];
- unset($functions[$dbfunction->name]);
- $function['classpath'] = empty($function['classpath']) ? null : $function['classpath'];
- $update = false;
- if ($dbfunction->classname != $function['classname']) {
- $dbfunction->classname = $function['classname'];
- $update = true;
- }
- if ($dbfunction->methodname != $function['methodname']) {
- $dbfunction->methodname = $function['methodname'];
- $update = true;
- }
- if ($dbfunction->classpath != $function['classpath']) {
- $dbfunction->classpath = $function['classpath'];
- $update = true;
- }
- $functioncapabilities = array_key_exists('capabilities', $function)?$function['capabilities']:'';
- if ($dbfunction->capabilities != $functioncapabilities) {
- $dbfunction->capabilities = $functioncapabilities;
- $update = true;
- }
- if (isset($function['services']) and is_array($function['services'])) {
- sort($function['services']);
- $functionservices = implode(',', $function['services']);
- } else {
- // Force null values in the DB.
- $functionservices = null;
- }
- if ($dbfunction->services != $functionservices) {
- // Now, we need to check if services were removed, in that case we need to remove the function from them.
- $servicesremoved = array_diff(explode(",", $dbfunction->services), explode(",", $functionservices));
- foreach ($servicesremoved as $removedshortname) {
- if ($externalserviceid = $DB->get_field('external_services', 'id', array("shortname" => $removedshortname))) {
- $DB->delete_records('external_services_functions', array('functionname' => $dbfunction->name,
- 'externalserviceid' => $externalserviceid));
- }
- }
- $dbfunction->services = $functionservices;
- $update = true;
- }
- if ($update) {
- $DB->update_record('external_functions', $dbfunction);
- }
- }
- foreach ($functions as $fname => $function) {
- $dbfunction = new stdClass();
- $dbfunction->name = $fname;
- $dbfunction->classname = $function['classname'];
- $dbfunction->methodname = $function['methodname'];
- $dbfunction->classpath = empty($function['classpath']) ? null : $function['classpath'];
- $dbfunction->component = $component;
- $dbfunction->capabilities = array_key_exists('capabilities', $function)?$function['capabilities']:'';
- if (isset($function['services']) and is_array($function['services'])) {
- sort($function['services']);
- $dbfunction->services = implode(',', $function['services']);
- } else {
- // Force null values in the DB.
- $dbfunction->services = null;
- }
- $dbfunction->id = $DB->insert_record('external_functions', $dbfunction);
- }
- unset($functions);
- // …
Large files files are truncated, but you can click here to view the full file