MDL-17458 upgrade logging implemented + a lot more refactoring + exceptions implemented in install/upgrade code + lang pack cleanup + some more improvements

This commit is contained in:
skodak
2009-01-31 20:07:32 +00:00
parent 9c421fab3b
commit 795a08adb7
17 changed files with 628 additions and 743 deletions
-287
View File
@@ -18,70 +18,6 @@ define('BLOCKS_PINNED_BOTH',2);
require_once($CFG->libdir.'/pagelib.php');
require_once($CFG->dirroot.'/course/lib.php'); // needed to solve all those: Call to undefined function: print_recent_activity() when adding Recent Activity
// Returns false if this block is incompatible with the current version of Moodle.
function block_is_compatible($blockname) {
global $CFG;
$file = @file($CFG->dirroot.'/blocks/'.$blockname.'/block_'.$blockname.'.php'); // ignore errors when file does not exist
if(empty($file)) {
return NULL;
}
foreach($file as $line) {
// If you find MoodleBlock (appearing in the class declaration) it's not compatible
if(strpos($line, 'MoodleBlock')) {
return false;
}
// But if we find a { it means the class declaration is over, so it's compatible
else if(strpos($line, '{')) {
return true;
}
}
return NULL;
}
// Returns the case-sensitive name of the class' constructor function. This includes both
// PHP5- and PHP4-style constructors. If no appropriate constructor can be found, returns NULL.
// If there is no such class, returns boolean false.
function get_class_constructor($classname) {
// Caching
static $constructors = array();
if(!class_exists($classname)) {
return false;
}
// Tests indicate this doesn't hurt even in PHP5.
$classname = strtolower($classname);
// Return cached value, if exists
if(isset($constructors[$classname])) {
return $constructors[$classname];
}
// Get a list of methods. After examining several different ways of
// doing the check, (is_callable, method_exists, function_exists etc)
// it seems that this is the most reliable one.
$methods = get_class_methods($classname);
// PHP5 constructor?
if(phpversion() >= '5') {
if(in_array('__construct', $methods)) {
return $constructors[$classname] = '__construct';
}
}
// If we have PHP5 but no magic constructor, we have to lowercase the methods
$methods = array_map('strtolower', $methods);
if(in_array($classname, $methods)) {
return $constructors[$classname] = $classname;
}
return $constructors[$classname] = NULL;
}
//This function retrieves a method-defined property of a class WITHOUT instantiating an object
function block_method_result($blockname, $method, $param = NULL) {
if(!block_load_class($blockname)) {
@@ -1069,227 +1005,4 @@ function blocks_repopulate_page($page) {
return true;
}
//This function finds all available blocks and install them
//into blocks table or do all the upgrade process if newer
function upgrade_blocks_plugins() {
global $CFG, $interactive, $DB, $SITE;
require_once($CFG->dirroot .'/blocks/moodleblock.class.php');
$updated_blocks = false;
$blocktitles = array();
$invalidblocks = array();
$validblocks = array();
$notices = array();
//Count the number of blocks in db
$blockcount = $DB->count_records('block');
//If there isn't records. This is the first install, so I remember it
$first_install = ($blockcount == 0);
if (!$blocks = get_list_of_plugins('blocks') ) {
print_error('noblocks', 'debug');
}
if (!class_exists('block_base')) {
print_error('noblockbase');
}
foreach ($blocks as $blockname) {
if ($blockname == 'NEWBLOCK') { // Someone has unzipped the template, ignore it
continue;
}
if(!block_is_compatible($blockname)) {
// This is an old-style block
//$notices[] = 'Block '. $blockname .' is not compatible with the current version of Mooodle and needs to be updated by a programmer.';
$invalidblocks[] = $blockname;
continue;
}
$fullblock = $CFG->dirroot .'/blocks/'. $blockname;
if ( is_readable($fullblock.'/block_'.$blockname.'.php')) {
include_once($fullblock.'/block_'.$blockname.'.php');
} else {
$notices[] = 'Block '. $blockname .': '. $fullblock .'/block_'. $blockname .'.php was not readable';
continue;
}
$newupgrade = false;
if ( @is_dir($fullblock .'/db/')) {
if ( @is_readable($fullblock .'/db/upgrade.php')) {
include_once($fullblock .'/db/upgrade.php'); // defines new upgrading function
$newupgrade = true;
}
}
$classname = 'block_'.$blockname;
if(!class_exists($classname)) {
$notices[] = 'Block '. $blockname .': '. $classname .' not implemented';
continue;
}
// Here is the place to see if the block implements a constructor (old style),
// an init() function (new style) or nothing at all (error time).
$constructor = get_class_constructor($classname);
if(empty($constructor)) {
// No constructor
$notices[] = 'Block '. $blockname .': class does not have a constructor';
$invalidblocks[] = $blockname;
continue;
}
$block = new stdClass; // This may be used to update the db below
$blockobj = new $classname; // This is what we 'll be testing
// Inherits from block_base?
if(!is_subclass_of($blockobj, 'block_base')) {
$notices[] = 'Block '. $blockname .': class does not inherit from block_base';
continue;
}
// OK, it's as we all hoped. For further tests, the object will do them itself.
if(!$blockobj->_self_test()) {
$notices[] = 'Block '. $blockname .': self test failed';
continue;
}
$block->version = $blockobj->get_version();
if (!isset($block->version)) {
$notices[] = 'Block '. $blockname .': has no version support. It must be updated by a programmer.';
continue;
}
$block->name = $blockname; // The name MUST match the directory
$blocktitle = $blockobj->get_title();
if ($currblock = $DB->get_record('block', array('name'=>$block->name))) {
if ($currblock->version == $block->version) {
// do nothing
} else if ($currblock->version < $block->version) {
$updated_blocks = true;
upgrade_started();
print_heading('New version of '.$blocktitle.' ('.$block->name.') exists');
@set_time_limit(0); // To allow slow databases to complete the long SQL
/// Run de old and new upgrade functions for the module
$newupgrade_function = 'xmldb_block_' . $block->name .'_upgrade';
/// Then, the new function if exists and the old one was ok
$newupgrade_status = true;
if ($newupgrade && function_exists($newupgrade_function)) {
$newupgrade_status = $newupgrade_function($currblock->version, $block);
} else if ($newupgrade) {
notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
$fullblock . '/db/upgrade.php');
}
/// Now analyze upgrade results
if ($newupgrade_status) { // No upgrading failed
// Set the block cron on upgrade
$block->cron = !empty($blockobj->cron) ? $blockobj->cron : 0;
// OK so far, now update the block record
$block->id = $currblock->id;
if (!$DB->update_record('block', $block)) {
print_error('cannotupdateblock', '', '', $block->name);
}
$component = 'block/'.$block->name;
if (!update_capabilities($component)) {
print_error('nopermissiontoupdateblock', '', '', $block->name);
}
// Update events
events_update_definition($component);
// Update message providers
require_once($CFG->libdir .'/messagelib.php'); // Messagelib functions
message_update_providers($component);
notify(get_string('blocksuccess', '', $blocktitle), 'notifysuccess');
} else {
notify('Upgrading block '. $block->name .' from '. $currblock->version .' to '. $block->version .' FAILED!');
}
print_upgrade_separator();
} else {
print_error('cannotdowngrade', 'debug', '', (object)array('oldversion'=>$currblock->version, 'newversion'=>$block->version));
}
} else { // block not installed yet, so install it
// If it allows multiples, start with it enabled
if ($blockobj->instance_allow_multiple()) {
$block->multiple = 1;
}
// Set the block cron on install
$block->cron = !empty($blockobj->cron) ? $blockobj->cron : 0;
// [pj] Normally this would be inline in the if, but we need to
// check for NULL (necessary for 4.0.5 <= PHP < 4.2.0)
$conflictblock = array_search($blocktitle, $blocktitles);
if ($conflictblock !== false && $conflictblock !== NULL) {
// Duplicate block titles are not allowed, they confuse people
// AND PHP's associative arrays ;)
print_error('blocknameconflict', '', '', (object)array('name'=>$block->name, 'conflict'=>$conflictblock));
}
$updated_blocks = true;
upgrade_started();
print_heading($block->name);
@set_time_limit(0); // To allow slow databases to complete the long SQL
/// Both old .sql files and new install.xml are supported
/// but we priorize install.xml (XMLDB) if present
if (file_exists($fullblock . '/db/install.xml')) {
$DB->get_manager()->install_from_xmldb_file($fullblock . '/db/install.xml'); //New method
}
$block->id = $DB->insert_record('block', $block);
$blockobj->after_install();
$component = 'block/'.$block->name;
update_capabilities($component);
// Update events
events_update_definition($component);
// Update message providers
require_once($CFG->libdir .'/messagelib.php'); // Messagelib functions
message_update_providers($component);
notify(get_string('blocksuccess', '', $blocktitle), 'notifysuccess');
print_upgrade_separator();
}
$blocktitles[$block->name] = $blocktitle;
}
if(!empty($notices)) {
foreach($notices as $notice) {
notify($notice);
}
}
// Finally, if we are in the first_install of BLOCKS setup frontpage and admin page blocks
if ($first_install) {
require_once($CFG->dirroot.'/'.$CFG->admin.'/pagelib.php');
//Iterate over each course - there should be only site course here now
if ($courses = $DB->get_records('course')) {
foreach ($courses as $course) {
$page = page_create_object(PAGE_COURSE_VIEW, $course->id);
blocks_repopulate_page($page);
}
}
page_map_class(PAGE_ADMIN, 'page_admin');
$page = page_create_object(PAGE_ADMIN, 0); // there must be some id number
blocks_repopulate_page($page);
}
return $updated_blocks;
}
?>