Merge branch 'MDL-41669-master' of git://github.com/sammarshallou/moodle

This commit is contained in:
Marina Glancy 2013-09-24 11:48:49 +10:00
commit d9fd72feb5
9 changed files with 182 additions and 20 deletions

View File

@ -120,6 +120,10 @@ if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
// Prepare the restore controller. We don't need a UI here as we will just use what
// ever the restore has (the user has just chosen).
$rc = new restore_controller($backupid, $course->id, backup::INTERACTIVE_YES, backup::MODE_IMPORT, $USER->id, $restoretarget);
// Start a progress section for the restore, which will consist of 2 steps
// (the precheck and then the actual restore).
$progress->start_progress('Restore process', 2);
$rc->set_progress($progress);
// Convert the backup if required.... it should NEVER happed
if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) {
@ -155,6 +159,9 @@ if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
// Delete the temp directory now
fulldelete($tempdestination);
// End restore section of progress tracking (restore/precheck).
$progress->end_progress();
// All progress complete. Hide progress area.
$progress->end_progress();
echo html_writer::end_div();

View File

@ -594,13 +594,17 @@ class restore_load_included_inforef_records extends restore_execution_step {
// Get all the included tasks
$tasks = restore_dbops::get_included_tasks($this->get_restoreid());
$progress = $this->task->get_progress();
$progress->start_progress($this->get_name(), count($tasks));
foreach ($tasks as $task) {
// Load the inforef.xml file if exists
$inforefpath = $task->get_taskbasepath() . '/inforef.xml';
if (file_exists($inforefpath)) {
restore_dbops::load_inforef_to_tempids($this->get_restoreid(), $inforefpath); // Load each inforef file to temp_ids
// Load each inforef file to temp_ids.
restore_dbops::load_inforef_to_tempids($this->get_restoreid(), $inforefpath, $progress);
}
}
$progress->end_progress();
}
}
@ -687,7 +691,8 @@ class restore_load_included_users extends restore_execution_step {
return;
}
$file = $this->get_basepath() . '/users.xml';
restore_dbops::load_users_to_tempids($this->get_restoreid(), $file); // Load needed users to temp_ids
// Load needed users to temp_ids.
restore_dbops::load_users_to_tempids($this->get_restoreid(), $file, $this->task->get_progress());
}
}
@ -708,7 +713,8 @@ class restore_process_included_users extends restore_execution_step {
if (!$this->task->get_setting_value('users')) { // No userinfo being restored, nothing to do
return;
}
restore_dbops::process_included_users($this->get_restoreid(), $this->task->get_courseid(), $this->task->get_userid(), $this->task->is_samesite());
restore_dbops::process_included_users($this->get_restoreid(), $this->task->get_courseid(),
$this->task->get_userid(), $this->task->is_samesite(), $this->task->get_progress());
}
}

View File

@ -54,7 +54,7 @@ echo $OUTPUT->header();
// Prepare a progress bar which can display optionally during long-running
// operations while setting up the UI.
$slowprogress = new core_backup_display_progress_if_slow();
$slowprogress = new core_backup_display_progress_if_slow(get_string('preparingui', 'backup'));
// Depending on the code branch above, $restore may be a restore_ui or it may
// be a restore_ui_independent_stage. Either way, this function exists.
$restore->set_progress_reporter($slowprogress);
@ -65,13 +65,20 @@ if (!$restore->is_independent() && $restore->enforce_changed_dependencies()) {
}
if (!$restore->is_independent()) {
// Use a temporary (disappearing) progress bar to show the precheck progress if any.
$precheckprogress = new core_backup_display_progress_if_slow(get_string('preparingdata', 'backup'));
$restore->get_controller()->set_progress($precheckprogress);
if ($restore->get_stage() == restore_ui::STAGE_PROCESS && !$restore->requires_substage()) {
try {
// Display an extra progress bar so that we can show the progress first.
// Div used to hide the 'progress' step once the page gets onto 'finished'.
echo html_writer::start_div('', array('id' => 'executionprogress'));
// Show the current restore state (header with bolded item).
echo $renderer->progress_bar($restore->get_progress_bar());
$restore->get_controller()->set_progress(new core_backup_display_progress());
// Start displaying the actual progress bar percentage.
$restore->get_controller()->set_progress(new core_backup_display_progress(true));
// Do actual restore.
$restore->execute();
// Hide this section because we are now going to make the page show 'finished'.
echo html_writer::end_div();
echo html_writer::script('document.getElementById("executionprogress").style.display = "none";');
} catch(Exception $e) {

View File

@ -109,18 +109,34 @@ abstract class restore_dbops {
/**
* Load one inforef.xml file to backup_ids table for future reference
*
* @param string $restoreid Restore id
* @param string $inforeffile File path
* @param core_backup_progress $progress Progress tracker
*/
public static function load_inforef_to_tempids($restoreid, $inforeffile) {
public static function load_inforef_to_tempids($restoreid, $inforeffile,
core_backup_progress $progress = null) {
if (!file_exists($inforeffile)) { // Shouldn't happen ever, but...
throw new backup_helper_exception('missing_inforef_xml_file', $inforeffile);
}
// Set up progress tracking (indeterminate).
if (!$progress) {
$progress = new core_backup_null_progress();
}
$progress->start_progress('Loading inforef.xml file');
// Let's parse, custom processor will do its work, sending info to DB
$xmlparser = new progressive_parser();
$xmlparser->set_file($inforeffile);
$xmlprocessor = new restore_inforef_parser_processor($restoreid);
$xmlparser->set_processor($xmlprocessor);
$xmlparser->set_progress($progress);
$xmlparser->process();
// Finish progress
$progress->end_progress();
}
/**
@ -400,18 +416,34 @@ abstract class restore_dbops {
/**
* Load the needed users.xml file to backup_ids table for future reference
*
* @param string $restoreid Restore id
* @param string $usersfile File path
* @param core_backup_progress $progress Progress tracker
*/
public static function load_users_to_tempids($restoreid, $usersfile) {
public static function load_users_to_tempids($restoreid, $usersfile,
core_backup_progress $progress = null) {
if (!file_exists($usersfile)) { // Shouldn't happen ever, but...
throw new backup_helper_exception('missing_users_xml_file', $usersfile);
}
// Set up progress tracking (indeterminate).
if (!$progress) {
$progress = new core_backup_null_progress();
}
$progress->start_progress('Loading users into temporary table');
// Let's parse, custom processor will do its work, sending info to DB
$xmlparser = new progressive_parser();
$xmlparser->set_file($usersfile);
$xmlprocessor = new restore_users_parser_processor($restoreid);
$xmlparser->set_processor($xmlprocessor);
$xmlparser->set_progress($progress);
$xmlparser->process();
// Finish progress.
$progress->end_progress();
}
/**
@ -1385,8 +1417,15 @@ abstract class restore_dbops {
* for each one (mapping / creation) and returning one array
* of problems in case something is wrong (lack of permissions,
* conficts)
*
* @param string $restoreid Restore id
* @param int $courseid Course id
* @param int $userid User id
* @param bool $samesite True if restore is to same site
* @param core_backup_progress $progress Progress reporter
*/
public static function precheck_included_users($restoreid, $courseid, $userid, $samesite) {
public static function precheck_included_users($restoreid, $courseid, $userid, $samesite,
core_backup_progress $progress) {
global $CFG, $DB;
// To return any problem found
@ -1409,8 +1448,14 @@ abstract class restore_dbops {
$cancreateuser = true;
}
// Prepare for reporting progress.
$conditions = array('backupid' => $restoreid, 'itemname' => 'user');
$max = $DB->count_records('backup_ids_temp', $conditions);
$done = 0;
$progress->start_progress('Checking users', $max);
// Iterate over all the included users
$rs = $DB->get_recordset('backup_ids_temp', array('backupid' => $restoreid, 'itemname' => 'user'), '', 'itemid, info');
$rs = $DB->get_recordset('backup_ids_temp', $conditions, '', 'itemid, info');
foreach ($rs as $recuser) {
$user = (object)backup_controller_dbops::decode_backup_temp_info($recuser->info);
@ -1447,8 +1492,11 @@ abstract class restore_dbops {
} else { // Shouldn't arrive here ever, something is for sure wrong. Exception
throw new restore_dbops_exception('restore_error_processing_user', $user->username);
}
$done++;
$progress->progress($done);
}
$rs->close();
$progress->end_progress();
return $problems;
}
@ -1458,12 +1506,19 @@ abstract class restore_dbops {
*
* Just wrap over precheck_included_users(), returning
* exception if any problem is found
*
* @param string $restoreid Restore id
* @param int $courseid Course id
* @param int $userid User id
* @param bool $samesite True if restore is to same site
* @param core_backup_progress $progress Optional progress tracker
*/
public static function process_included_users($restoreid, $courseid, $userid, $samesite) {
public static function process_included_users($restoreid, $courseid, $userid, $samesite,
core_backup_progress $progress = null) {
global $DB;
// Just let precheck_included_users() to do all the hard work
$problems = self::precheck_included_users($restoreid, $courseid, $userid, $samesite);
$problems = self::precheck_included_users($restoreid, $courseid, $userid, $samesite, $progress);
// With problems, throw exception, shouldn't happen if prechecks were originally
// executed, so be radical here.

View File

@ -43,7 +43,7 @@ abstract class restore_prechecks_helper {
*
* Returns empty array or warnings/errors array
*/
public static function execute_prechecks($controller, $droptemptablesafter = false) {
public static function execute_prechecks(restore_controller $controller, $droptemptablesafter = false) {
global $CFG;
$errors = array();
@ -57,16 +57,31 @@ abstract class restore_prechecks_helper {
$courseid = $controller->get_courseid();
$userid = $controller->get_userid();
$rolemappings = $controller->get_info()->role_mappings;
$progress = $controller->get_progress();
// Start tracking progress. There are currently 8 major steps, corresponding
// to $majorstep++ lines in this code; we keep track of the total so as to
// verify that it's still correct. If you add a major step, you need to change
// the total here.
$majorstep = 1;
$majorsteps = 8;
$progress->start_progress('Carrying out pre-restore checks', $majorsteps);
// Load all the included tasks to look for inforef.xml files
$inforeffiles = array();
$tasks = restore_dbops::get_included_tasks($restoreid);
$progress->start_progress('Listing inforef files', count($tasks));
$minorstep = 1;
foreach ($tasks as $task) {
// Add the inforef.xml file if exists
$inforefpath = $task->get_taskbasepath() . '/inforef.xml';
if (file_exists($inforefpath)) {
$inforeffiles[] = $inforefpath;
}
$progress->progress($minorstep++);
}
$progress->end_progress();
$progress->progress($majorstep++);
// Create temp tables
restore_controller_dbops::create_restore_temp_tables($controller->get_restoreid());
@ -108,18 +123,31 @@ abstract class restore_prechecks_helper {
}
// Load all the inforef files, we are going to need them
$progress->start_progress('Loading temporary IDs', count($inforeffiles));
$minorstep = 1;
foreach ($inforeffiles as $inforeffile) {
restore_dbops::load_inforef_to_tempids($restoreid, $inforeffile); // Load each inforef file to temp_ids
// Load each inforef file to temp_ids.
restore_dbops::load_inforef_to_tempids($restoreid, $inforeffile, $progress);
$progress->progress($minorstep++);
}
$progress->end_progress();
$progress->progress($majorstep++);
// If restoring users, check we are able to create all them
if ($restoreusers) {
$file = $controller->get_plan()->get_basepath() . '/users.xml';
restore_dbops::load_users_to_tempids($restoreid, $file); // Load needed users to temp_ids
if ($problems = restore_dbops::precheck_included_users($restoreid, $courseid, $userid, $samesite)) {
// Load needed users to temp_ids.
restore_dbops::load_users_to_tempids($restoreid, $file, $progress);
$progress->progress($majorstep++);
if ($problems = restore_dbops::precheck_included_users($restoreid, $courseid, $userid, $samesite, $progress)) {
$errors = array_merge($errors, $problems);
}
} else {
// To ensure consistent number of steps in progress tracking,
// mark progress even though we didn't do anything.
$progress->progress($majorstep++);
}
$progress->progress($majorstep++);
// Note: restore won't create roles at all. Only mapping/skip!
$file = $controller->get_plan()->get_basepath() . '/roles.xml';
@ -128,6 +156,7 @@ abstract class restore_prechecks_helper {
$errors = array_key_exists('errors', $problems) ? array_merge($errors, $problems['errors']) : $errors;
$warnings = array_key_exists('warnings', $problems) ? array_merge($warnings, $problems['warnings']) : $warnings;
}
$progress->progress($majorstep++);
// Check we are able to restore and the categories and questions
$file = $controller->get_plan()->get_basepath() . '/questions.xml';
@ -136,8 +165,9 @@ abstract class restore_prechecks_helper {
$errors = array_key_exists('errors', $problems) ? array_merge($errors, $problems['errors']) : $errors;
$warnings = array_key_exists('warnings', $problems) ? array_merge($warnings, $problems['warnings']) : $warnings;
}
$progress->progress($majorstep++);
// Prepare results and return
// Prepare results.
$results = array();
if (!empty($errors)) {
$results['errors'] = $errors;
@ -149,6 +179,14 @@ abstract class restore_prechecks_helper {
if (!empty($results) || $droptemptablesafter) {
restore_controller_dbops::drop_restore_temp_tables($controller->get_restoreid());
}
// Finish progress and check we got the initial number of steps right.
$progress->progress($majorstep++);
if ($majorstep != $majorsteps) {
throw new coding_exception('Progress step count wrong: ' . $majorstep);
}
$progress->end_progress();
return $results;
}
}

View File

@ -101,8 +101,14 @@ abstract class restore_structure_step extends restore_step {
$xmlprocessor->add_path($element->get_path(), $element->is_grouped());
}
// Set up progress tracking.
$progress = $this->get_task()->get_progress();
$progress->start_progress($this->get_name(), core_backup_progress::INDETERMINATE);
$xmlparser->set_progress($progress);
// And process it, dispatch to target methods in step will start automatically
$xmlparser->process();
$progress->end_progress();
// Have finished, launch the after_execute method of all the processing objects
$this->launch_after_execute_methods();

View File

@ -43,6 +43,11 @@ class core_backup_display_progress_if_slow extends core_backup_display_progress
*/
protected $id;
/**
* @var string Text to display in heading if bar appears
*/
protected $heading;
/**
* @var int Time at which the progress bar should display (if it isn't yet)
*/
@ -52,23 +57,38 @@ class core_backup_display_progress_if_slow extends core_backup_display_progress
* Constructs the progress reporter. This will not output HTML just yet,
* until the required delay time expires.
*
* @param string $heading Text to display above bar (if it appears); '' for none
* @param int $delay Delay time (default 5 seconds)
*/
public function __construct($delay = self::DEFAULT_DISPLAY_DELAY) {
public function __construct($heading, $delay = self::DEFAULT_DISPLAY_DELAY) {
// Set start time based on delay.
$this->starttime = time() + $delay;
$this->heading = $heading;
parent::__construct(false);
}
/**
* Adds a div around the parent display so it can be hidden.
* Starts displaying the progress bar, with optional heading and a special
* div so it can be hidden later.
*
* @see core_backup_display_progress::start_html()
*/
public function start_html() {
global $OUTPUT;
$this->id = 'core_backup_display_progress_if_slow' . self::$nextid;
self::$nextid++;
echo html_writer::start_div('', array('id' => $this->id));
// Containing div includes a CSS class so that it can be themed if required,
// and an id so it can be automatically hidden at end.
echo html_writer::start_div('core_backup_display_progress_if_slow',
array('id' => $this->id));
// Display optional heading.
if ($this->heading !== '') {
echo $OUTPUT->heading($this->heading, 3);
}
// Use base class to display progress bar.
parent::start_html();
}

View File

@ -67,6 +67,11 @@ class progressive_parser {
protected $prevlevel; // level of the previous tag processed - to detect pushing places
protected $currtag; // name/value/attributes of the tag being processed
/**
* @var core_backup_progress Progress tracker called for each action
*/
protected $progress;
public function __construct($case_folding = false) {
$this->xml_parser = xml_parser_create('UTF-8');
xml_parser_set_option($this->xml_parser, XML_OPTION_CASE_FOLDING, $case_folding);
@ -118,6 +123,18 @@ class progressive_parser {
$this->processor = $processor;
}
/**
* Sets the progress tracker for the parser. If set, the tracker will be
* called to report indeterminate progress for each chunk of XML.
*
* The caller should have already called start_progress on the progress tracker.
*
* @param core_backup_progress $progress Progress tracker
*/
public function set_progress(core_backup_progress $progress) {
$this->progress = $progress;
}
/*
* Process the XML, delegating found chunks to the @progressive_parser_processor
*/
@ -167,6 +184,10 @@ class progressive_parser {
protected function publish($data) {
$this->processor->receive_chunk($data);
if (!empty($this->progress)) {
// Report indeterminate progress.
$this->progress->progress();
}
}
/**

View File

@ -174,6 +174,8 @@ $string['nomatchingcourses'] = 'There are no courses to display';
$string['norestoreoptions'] = 'There are no categories or existing courses you can restore to.';
$string['originalwwwroot'] = 'URL of backup';
$string['previousstage'] = 'Previous';
$string['preparingui'] = 'Preparing to display page';
$string['preparingdata'] = 'Preparing data';
$string['qcategory2coursefallback'] = 'The questions category "{$a->name}", originally at system/course category context in backup file, will be created at course context by restore';
$string['qcategorycannotberestored'] = 'The questions category "{$a->name}" cannot be created by restore';
$string['question2coursefallback'] = 'The questions category "{$a->name}", originally at system/course category context in backup file, will be created at course context by restore';