<?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/>.
/**
* Backup user interface stages
*
* This file contains the classes required to manage the stages that make up the
* backup user interface.
* These will be primarily operated a {@link backup_ui} instance.
*
* @package core_backup
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Abstract stage class
*
* This class should be extended by all backup stages (a requirement of many backup ui functions).
* Each stage must then define two abstract methods
* - process : To process the stage
* - initialise_stage_form : To get a backup_moodleform instance for the stage
*
* @package core_backup
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class backup_ui_stage extends base_ui_stage {
/**
* Constructor.
*
* @param backup_ui $ui
* @param array $params
*/
public function __construct(backup_ui $ui, array $params = null) {
parent::__construct($ui, $params);
}
/**
* The backup id from the backup controller
* @return string
*/
final public function get_backupid() {
return $this->get_uniqueid();
}
}
/**
* Class representing the initial stage of a backup.
*
* In this stage the user is required to set the root level settings.
*
* @package core_backup
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class backup_ui_stage_initial extends backup_ui_stage {
/**
* When set to true we skip all stages and jump to immediately processing the backup.
* @var bool
*/
protected $oneclickbackup = false;
/**
* Initial backup stage constructor
* @param backup_ui $ui
* @param array $params
*/
public function __construct(backup_ui $ui, array $params = null) {
$this->stage = backup_ui::STAGE_INITIAL;
parent::__construct($ui, $params);
}
/**
* Processes the initial backup stage
* @param base_moodleform $m
* @return int The number of changes
*/
public function process(base_moodleform $m = null) {
$form = $this->initialise_stage_form();
if ($form->is_cancelled()) {
$this->ui->cancel_process();
}
$data = $form->get_data();
if ($data && confirm_sesskey()) {
if (isset($data->oneclickbackup)) {
$this->oneclickbackup = true;
}
$tasks = $this->ui->get_tasks();
$changes = 0;
foreach ($tasks as &$task) {
// We are only interesting in the backup root task for this stage.
if ($task instanceof backup_root_task) {
// Get all settings into a var so we can iterate by reference.
$settings = $task->get_settings();
foreach ($settings as &$setting) {
$name = $setting->get_ui_name();
if (isset($data->$name) && $data->$name != $setting->get_value()) {
$setting->set_value($data->$name);
$changes++;
} else if (!isset($data->$name) && $setting->get_value() &&
$setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX &&
$setting->get_status() !== backup_setting::LOCKED_BY_HIERARCHY) {
$setting->set_value(0);
$changes++;
}
}
}
}
// Return the number of changes the user made.
return $changes;
} else {
return false;
}
}
/**
* Gets the next stage for the backup.
*
* We override this function to implement the one click backup.
* When the user performs a one click backup we jump straight to the final stage.
*
* @return int
*/
public function get_next_stage() {
if ($this->oneclickbackup) {
// Its a one click backup.
// The default filename is backup.mbz, this normally gets set to something useful in the confirmation stage.
// because we skipped that stage we must manually set this to a useful value.
$tasks = $this->ui->get_tasks();
foreach ($tasks as $task) {
if ($task instanceof backup_root_task) {
// Find the filename setting.
$setting = $task->get_setting('filename');
if ($setting) {
// Use the helper objects to get a useful name.
$filename = backup_plan_dbops::get_default_backup_filename(
$this->ui->get_format(),
$this->ui->get_type(),
$this->ui->get_controller_id(),
$this->ui->get_setting_value('users'),
$this->ui->get_setting_value('anonymize'),
false,
(bool)$this->ui->get_setting_value('files')
);
$setting->set_value($filename);
}
}
}
return backup_ui::STAGE_FINAL;
}
return parent::get_next_stage();
}
/**
* Initialises the backup_moodleform instance for this stage
*
* @return backup_initial_form
*/
protected function initialise_stage_form() {
global $PAGE;
if ($this->stageform === null) {
$form = new backup_initial_form($this, $PAGE->url);
// Store as a variable so we can iterate by reference.
$tasks = $this->ui->get_tasks();
// Iterate all tasks by reference.
$add_settings = array();
$dependencies = array();
foreach ($tasks as &$task) {
// For the initial stage we are only interested in the root settings.
if ($task instanceof backup_root_task) {
if ($this->ui instanceof import_ui) {
$form->add_heading('rootsettings', get_string('importrootsettings', 'backup'));
} else {
$form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
}
$settings = $task->get_settings();
// First add all settings except the filename setting.
foreach ($settings as &$setting) {
if ($setting->get_name() == 'filename') {
continue;
}
$add_settings[] = array($setting, $task);
}
// Then add all dependencies.
foreach ($settings as &$setting) {
if ($setting->get_name() == 'filename') {
continue;
}
$dependencies[] = $setting;
}
}
}
// Add all settings at once.
$form->add_settings($add_settings);
// Add dependencies.
foreach ($dependencies as $depsetting) {
$form->add_dependencies($depsetting);
}
$this->stageform = $form;
}
// Return the form.
return $this->stageform;
}
}
/**
* Schema stage of backup process
*
* During the schema stage the user is required to set the settings that relate
* to the area that they are backing up as well as its children.
*
* @package core_backup
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class backup_ui_stage_schema extends backup_ui_stage {
/**
* @var int Maximum number of settings to add to form at once
*/
const MAX_SETTINGS_BATCH = 1000;
/**
* Schema stage constructor
* @param backup_ui $ui
* @param array $params
*/
public function __construct(backup_ui $ui, array $params = null) {
$this->stage = backup_ui::STAGE_SCHEMA;
parent::__construct($ui, $params);
}
/**
* Processes the schema stage
*
* @param base_moodleform $form
* @return int The number of changes the user made
*/
public function process(base_moodleform $form = null) {
$form = $this->initialise_stage_form();
// Check it wasn't cancelled.
if ($form->is_cancelled()) {
$this->ui->cancel_process();
}
// Check it has been submit.
$data = $form->get_data();
if ($data && confirm_sesskey()) {
// Get the tasks into a var so we can iterate by reference.
$tasks = $this->ui->get_tasks();
$changes = 0;
// Iterate all tasks by reference.
foreach ($tasks as &$task) {
// We are only interested in schema settings.
if (!($task instanceof backup_root_task)) {
// Store as a variable so we can iterate by reference.
$settings = $task->get_settings();
// Iterate by reference.
foreach ($settings as &$setting) {
$name = $setting->get_ui_name();
if (isset($data->$name) && $data->$name != $setting->get_value()) {
$setting->set_value($data->$name);
$changes++;
} else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
$setting->set_value(0);
$changes++;
}
}
}
}
// Return the number of changes the user made.
return $changes;
} else {
return false;
}
}
/**
* Creates the backup_schema_form instance for this stage
*
* @return backup_schema_form
*/
protected function initialise_stage_form() {
global $PAGE;
if ($this->stageform === null) {
$form = new backup_schema_form($this, $PAGE->url);
$tasks = $this->ui->get_tasks();
$content = '';
$courseheading = false;
$add_settings = array();
$dependencies = array();
// Track progress through each stage.
$progress = $this->ui->get_controller()->get_progress();
$progress->start_progress('Initialise stage form', 3);
// Get settings for all tasks.
$progress->start_progress('', count($tasks));
$done = 1;
foreach ($tasks as $task) {
if (!($task instanceof backup_root_task)) {
if (!$courseheading) {
// If we haven't already display a course heading to group nicely.
$form->add_heading('coursesettings', get_string('includeactivities', 'backup'));
$courseheading = true;
}
// First add each setting.
foreach ($task->get_settings() as $setting) {
$add_settings[] = array($setting, $task);
}
// The add all the dependencies.
foreach ($task->get_settings() as $setting) {
$dependencies[] = $setting;
}
} else if ($this->ui->enforce_changed_dependencies()) {
// Only show these settings if dependencies changed them.
// Add a root settings heading to group nicely.
$form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
// Iterate all settings and add them to the form as a fixed
// setting. We only want schema settings to be editable.
foreach ($task->get_settings() as $setting) {
if ($setting->get_name() != 'filename') {
$form->add_fixed_setting($setting, $task);
}
}
}
// Update progress.
$progress->progress($done++);
}
$progress->end_progress();
// Add settings for tasks in batches of up to 1000. Adding settings
// in larger batches improves performance, but if it takes too long,
// we won't be able to update the progress bar so the backup might.
// time out. 1000 is chosen to balance this.
$numsettings = count($add_settings);
$progress->start_progress('', ceil($numsettings / self::MAX_SETTINGS_BATCH));
$start = 0;
$done = 1;
while ($start < $numsettings) {
$length = min(self::MAX_SETTINGS_BATCH, $numsettings - $start);
$form->add_settings(array_slice($add_settings, $start, $length));
$start += $length;
$progress->progress($done++);
}
$progress->end_progress();
$progress->start_progress('', count($dependencies));
$done = 1;
foreach ($dependencies as $depsetting) {
$form->add_dependencies($depsetting);
$progress->progress($done++);
}
$progress->end_progress();
// End overall progress through creating form.
$progress->end_progress();
$this->stageform = $form;
}
return $this->stageform;
}
}
/**
* Confirmation stage
*
* On this stage the user reviews the setting for the backup and can change the filename
* of the file that will be generated.
*
* @package core_backup
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class backup_ui_stage_confirmation extends backup_ui_stage {
/**
* Constructs the stage
* @param backup_ui $ui
* @param array $params
*/
public function __construct($ui, array $params = null) {
$this->stage = backup_ui::STAGE_CONFIRMATION;
parent::__construct($ui, $params);
}
/**
* Processes the confirmation stage
*
* @param base_moodleform $form
* @return int The number of changes the user made
*/
public function process(base_moodleform $form = null) {
$form = $this->initialise_stage_form();
// Check it hasn't been cancelled.
if ($form->is_cancelled()) {
$this->ui->cancel_process();
}
$data = $form->get_data();
if ($data && confirm_sesskey()) {
// Collect into a variable so we can iterate by reference.
$tasks = $this->ui->get_tasks();
$changes = 0;
// Iterate each task by reference.
foreach ($tasks as &$task) {
if ($task instanceof backup_root_task) {
// At this stage all we are interested in is the filename setting.
$setting = $task->get_setting('filename');
$name = $setting->get_ui_name();
if (isset($data->$name) && $data->$name != $setting->get_value()) {
$setting->set_value($data->$name);
$changes++;
}
}
}
// Return the number of changes the user made.
return $changes;
} else {
return false;
}
}
/**
* Creates the backup_confirmation_form instance this stage requires
*
* @return backup_confirmation_form
*/
protected function initialise_stage_form() {
global $PAGE;
if ($this->stageform === null) {
// Get the form.
$form = new backup_confirmation_form($this, $PAGE->url);
$content = '';
$courseheading = false;
foreach ($this->ui->get_tasks() as $task) {
if ($setting = $task->get_setting('filename')) {
$form->add_heading('filenamesetting', get_string('filename', 'backup'));
if ($setting->get_value() == 'backup.mbz') {
$format = $this->ui->get_format();
$type = $this->ui->get_type();
$id = $this->ui->get_controller_id();
$users = $this->ui->get_setting_value('users');
$anonymised = $this->ui->get_setting_value('anonymize');
$files = (bool)$this->ui->get_setting_value('files');
$filename = backup_plan_dbops::get_default_backup_filename(
$format,
$type,
$id,
$users,
$anonymised,
false,
$files);
$setting->set_value($filename);
}
$form->add_setting($setting, $task);
break;
}
}
// Track progress through tasks.
$progress = $this->ui->get_controller()->get_progress();
$tasks = $this->ui->get_tasks();
$progress->start_progress('initialise_stage_form', count($tasks));
$done = 1;
foreach ($tasks as $task) {
if ($task instanceof backup_root_task) {
// If its a backup root add a root settings heading to group nicely.
if ($this->ui instanceof import_ui) {
$form->add_heading('rootsettings', get_string('importrootsettings', 'backup'));
} else {
$form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
}
} else if (!$courseheading) {
// We haven't already add a course heading.
$form->add_heading('coursesettings', get_string('includeditems', 'backup'));
$courseheading = true;
}
// Iterate all settings, doesnt need to happen by reference.
foreach ($task->get_settings() as $setting) {
// For this stage only the filename setting should be editable.
if ($setting->get_name() != 'filename') {
$form->add_fixed_setting($setting, $task);
}
}
// Update progress.
$progress->progress($done++);
}
$progress->end_progress();
$this->stageform = $form;
}
return $this->stageform;
}
}
/**
* Final stage of backup
*
* This stage is special in that it is does not make use of a form. The reason for
* this is the order of procession of backup at this stage.
* The processesion is:
* 1. The final stage will be intialise.
* 2. The confirmation stage will be processed.
* 3. The backup will be executed
* 4. The complete stage will be loaded by execution
* 5. The complete stage will be displayed
*
* This highlights that we neither need a form nor a display method for this stage
* we simply need to process.
*
* @package core_backup
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class backup_ui_stage_final extends backup_ui_stage {
/**
* Constructs the final stage
* @param backup_ui $ui
* @param array $params
*/
public function __construct(backup_ui $ui, array $params = null) {
$this->stage = backup_ui::STAGE_FINAL;
parent::__construct($ui, $params);
}
/**
* Processes the final stage.
*
* In this case it ALWAYS passes processing to the previous stage (confirmation)
*
* @param base_moodleform $form
* @return bool
*/
public function process(base_moodleform $form = null) {
return true;
}
/**
* should NEVER be called... throws an exception
*/
protected function initialise_stage_form() {
throw new backup_ui_exception('backup_ui_must_execute_first');
}
/**
* should NEVER be called... throws an exception
*
* @throws backup_ui_exception always
* @param core_backup_renderer $renderer
* @return void
*/
public function display(core_backup_renderer $renderer) {
throw new backup_ui_exception('backup_ui_must_execute_first');
}
}
/**
* The completed backup stage
*
* At this stage everything is done and the user will be redirected to view the
* backup file in the file browser.
*
* @package core_backup
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class backup_ui_stage_complete extends backup_ui_stage_final {
/**
* The results of the backup execution
* @var array
*/
protected $results;
/**
* Constructs the complete backup stage
*
* @param backup_ui $ui
* @param array $params
* @param array $results
*/
public function __construct(backup_ui $ui, array $params = null, array $results = null) {
$this->results = $results;
parent::__construct($ui, $params);
$this->stage = backup_ui::STAGE_COMPLETE;
}
/**
* Displays the completed backup stage.
*
* Currently this just involves redirecting to the file browser with an
* appropriate message.
*
* @param core_backup_renderer $renderer
* @return string HTML code to echo
*/
public function display(core_backup_renderer $renderer) {
// Get the resulting stored_file record.
$type = $this->get_ui()->get_controller()->get_type();
$courseid = $this->get_ui()->get_controller()->get_courseid();
switch ($type) {
case 'activity':
$cmid = $this->get_ui()->get_controller()->get_id();
$cm = get_coursemodule_from_id(null, $cmid, $courseid);
$modcontext = context_module::instance($cm->id);
$restorerul = new moodle_url('/backup/restorefile.php', array('contextid' => $modcontext->id));
break;
case 'course':
default:
$coursecontext = context_course::instance($courseid);
$restorerul = new moodle_url('/backup/restorefile.php', array('contextid' => $coursecontext->id));
}
$output = '';
$output .= $renderer->box_start();
if (!empty($this->results['include_file_references_to_external_content'])) {
$output .= $renderer->notification(get_string('filereferencesincluded', 'backup'), 'notifyproblem');
}
if (!empty($this->results['missing_files_in_pool'])) {
$output .= $renderer->notification(get_string('missingfilesinpool', 'backup'), 'notifyproblem');
}
$output .= $renderer->get_samesite_notification();
$output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
< $output .= $renderer->continue_button($restorerul);
> $output .= $renderer->continue_button($restorerul, 'get');
$output .= $renderer->box_end();
return $output;
}
}