3 // This file is part of Moodle - http://moodle.org/
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
19 * Backup user interface stages
21 * This file contains the classes required to manage the stages that make up the
22 * backup user interface.
23 * These will be primarily operated a {@see backup_ui} instance.
26 * @copyright 2010 Sam Hemelryk
27 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31 * Abstract stage class
33 * This class should be extended by all backup stages (a requirement of many backup ui functions).
34 * Each stage must then define two abstract methods
35 * - process : To process the stage
36 * - initialise_stage_form : To get a backup_moodleform instance for the stage
38 * @copyright 2010 Sam Hemelryk
39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 abstract class backup_ui_stage extends base_ui_stage {
43 public function __construct(backup_ui $ui, array $params = null) {
44 parent::__construct($ui, $params);
47 * The backup id from the backup controller
50 final public function get_backupid() {
51 return $this->get_uniqueid();
56 * Class representing the initial stage of a backup.
58 * In this stage the user is required to set the root level settings.
60 * @copyright 2010 Sam Hemelryk
61 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
63 class backup_ui_stage_initial extends backup_ui_stage {
66 * When set to true we skip all stages and jump to immediately processing the backup.
69 protected $oneclickbackup = false;
72 * Initial backup stage constructor
73 * @param backup_ui $ui
75 public function __construct(backup_ui $ui, array $params=null) {
76 $this->stage = backup_ui::STAGE_INITIAL;
77 parent::__construct($ui, $params);
81 * Processes the initial backup stage
82 * @param backup_moodleform $form
83 * @return int The number of changes
85 public function process(base_moodleform $m = null) {
87 $form = $this->initialise_stage_form();
89 if ($form->is_cancelled()) {
90 $this->ui->cancel_process();
93 $data = $form->get_data();
94 if ($data && confirm_sesskey()) {
95 if (isset($data->oneclickbackup)) {
96 $this->oneclickbackup = true;
98 $tasks = $this->ui->get_tasks();
100 foreach ($tasks as &$task) {
101 // We are only interesting in the backup root task for this stage
102 if ($task instanceof backup_root_task) {
103 // Get all settings into a var so we can iterate by reference
104 $settings = $task->get_settings();
105 foreach ($settings as &$setting) {
106 $name = $setting->get_ui_name();
107 if (isset($data->$name) && $data->$name != $setting->get_value()) {
108 $setting->set_value($data->$name);
110 } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
111 $setting->set_value(0);
117 // Return the number of changes the user made
125 * Gets the next stage for the backup.
127 * We override this function to implement the one click backup.
128 * When the user performs a one click backup we jump straight to the final stage.
132 public function get_next_stage() {
133 if ($this->oneclickbackup) {
134 // Its a one click backup.
135 // The default filename is backup.mbz, this normally gets set to something useful in the confirmation stage.
136 // because we skipped that stage we must manually set this to a useful value.
137 $tasks = $this->ui->get_tasks();
138 foreach ($tasks as $task) {
139 if ($task instanceof backup_root_task) {
140 // Find the filename setting.
141 $setting = $task->get_setting('filename');
143 // Use the helper objects to get a useful name.
144 $filename = backup_plan_dbops::get_default_backup_filename(
145 $this->ui->get_format(),
146 $this->ui->get_type(),
147 $this->ui->get_controller_id(),
148 $this->ui->get_setting_value('users'),
149 $this->ui->get_setting_value('anonymize')
151 $setting->set_value($filename);
155 return backup_ui::STAGE_FINAL;
157 return parent::get_next_stage();
161 * Initialises the backup_moodleform instance for this stage
163 * @return backup_initial_form
165 protected function initialise_stage_form() {
167 if ($this->stageform === null) {
168 $form = new backup_initial_form($this, $PAGE->url);
169 // Store as a variable so we can iterate by reference
170 $tasks = $this->ui->get_tasks();
171 // Iterate all tasks by reference
172 $add_settings = array();
173 $dependencies = array();
174 foreach ($tasks as &$task) {
175 // For the initial stage we are only interested in the root settings
176 if ($task instanceof backup_root_task) {
177 $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
178 $settings = $task->get_settings();
179 // First add all settings except the filename setting
180 foreach ($settings as &$setting) {
181 if ($setting->get_name() == 'filename') {
184 $add_settings[] = array($setting, $task);
186 // Then add all dependencies
187 foreach ($settings as &$setting) {
188 if ($setting->get_name() == 'filename') {
191 $dependencies[] = $setting;
195 // Add all settings at once.
196 $form->add_settings($add_settings);
198 foreach ($dependencies as $depsetting) {
199 $form->add_dependencies($depsetting);
201 $this->stageform = $form;
204 return $this->stageform;
209 * Schema stage of backup process
211 * During the schema stage the user is required to set the settings that relate
212 * to the area that they are backing up as well as its children.
214 * @copyright 2010 Sam Hemelryk
215 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
217 class backup_ui_stage_schema extends backup_ui_stage {
219 * @var int Maximum number of settings to add to form at once
221 const MAX_SETTINGS_BATCH = 1000;
224 * Schema stage constructor
225 * @param backup_moodleform $ui
227 public function __construct(backup_ui $ui, array $params=null) {
228 $this->stage = backup_ui::STAGE_SCHEMA;
229 parent::__construct($ui, $params);
232 * Processes the schema stage
234 * @param backup_moodleform|null $form
235 * @return int The number of changes the user made
237 public function process(base_moodleform $form = null) {
238 $form = $this->initialise_stage_form();
239 // Check it wasn't cancelled
240 if ($form->is_cancelled()) {
241 $this->ui->cancel_process();
244 // Check it has been submit
245 $data = $form->get_data();
246 if ($data && confirm_sesskey()) {
247 // Get the tasks into a var so we can iterate by reference
248 $tasks = $this->ui->get_tasks();
250 // Iterate all tasks by reference
251 foreach ($tasks as &$task) {
252 // We are only interested in schema settings
253 if (!($task instanceof backup_root_task)) {
254 // Store as a variable so we can iterate by reference
255 $settings = $task->get_settings();
256 // Iterate by reference
257 foreach ($settings as &$setting) {
258 $name = $setting->get_ui_name();
259 if (isset($data->$name) && $data->$name != $setting->get_value()) {
260 $setting->set_value($data->$name);
262 } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
263 $setting->set_value(0);
269 // Return the number of changes the user made
276 * Creates the backup_schema_form instance for this stage
278 * @return backup_schema_form
280 protected function initialise_stage_form() {
282 if ($this->stageform === null) {
283 $form = new backup_schema_form($this, $PAGE->url);
284 $tasks = $this->ui->get_tasks();
286 $courseheading = false;
287 $add_settings = array();
288 $dependencies = array();
290 // Track progress through each stage.
291 $progress = $this->ui->get_controller()->get_progress();
292 $progress->start_progress('Initialise stage form', 3);
294 // Get settings for all tasks.
295 $progress->start_progress('', count($tasks));
297 foreach ($tasks as $task) {
298 if (!($task instanceof backup_root_task)) {
299 if (!$courseheading) {
300 // If we havn't already display a course heading to group nicely
301 $form->add_heading('coursesettings', get_string('includeactivities', 'backup'));
302 $courseheading = true;
304 // First add each setting
305 foreach ($task->get_settings() as $setting) {
306 $add_settings[] = array($setting, $task);
308 // The add all the dependencies
309 foreach ($task->get_settings() as $setting) {
310 $dependencies[] = $setting;
312 } else if ($this->ui->enforce_changed_dependencies()) {
313 // Only show these settings if dependencies changed them.
314 // Add a root settings heading to group nicely
315 $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
316 // Iterate all settings and add them to the form as a fixed
317 // setting. We only want schema settings to be editable
318 foreach ($task->get_settings() as $setting) {
319 if ($setting->get_name() != 'filename') {
320 $form->add_fixed_setting($setting, $task);
325 $progress->progress($done++);
327 $progress->end_progress();
329 // Add settings for tasks in batches of up to 1000. Adding settings
330 // in larger batches improves performance, but if it takes too long,
331 // we won't be able to update the progress bar so the backup might
332 // time out. 1000 is chosen to balance this.
333 $numsettings = count($add_settings);
334 $progress->start_progress('', ceil($numsettings / self::MAX_SETTINGS_BATCH));
337 while($start < $numsettings) {
338 $length = min(self::MAX_SETTINGS_BATCH, $numsettings - $start);
339 $form->add_settings(array_slice($add_settings, $start, $length));
341 $progress->progress($done++);
343 $progress->end_progress();
345 $progress->start_progress('', count($dependencies));
347 foreach ($dependencies as $depsetting) {
348 $form->add_dependencies($depsetting);
349 $progress->progress($done++);
351 $progress->end_progress();
353 // End overall progress through creating form.
354 $progress->end_progress();
355 $this->stageform = $form;
357 return $this->stageform;
364 * On this stage the user reviews the setting for the backup and can change the filename
365 * of the file that will be generated.
367 * @copyright 2010 Sam Hemelryk
368 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
370 class backup_ui_stage_confirmation extends backup_ui_stage {
372 * Constructs the stage
373 * @param backup_ui $ui
375 public function __construct($ui, array $params=null) {
376 $this->stage = backup_ui::STAGE_CONFIRMATION;
377 parent::__construct($ui, $params);
380 * Processes the confirmation stage
382 * @param backup_moodleform $form
383 * @return int The number of changes the user made
385 public function process(base_moodleform $form = null) {
386 $form = $this->initialise_stage_form();
387 // Check it hasn't been cancelled
388 if ($form->is_cancelled()) {
389 $this->ui->cancel_process();
392 $data = $form->get_data();
393 if ($data && confirm_sesskey()) {
394 // Collect into a variable so we can iterate by reference
395 $tasks = $this->ui->get_tasks();
397 // Iterate each task by reference
398 foreach ($tasks as &$task) {
399 if ($task instanceof backup_root_task) {
400 // At this stage all we are interested in is the filename setting
401 $setting = $task->get_setting('filename');
402 $name = $setting->get_ui_name();
403 if (isset($data->$name) && $data->$name != $setting->get_value()) {
404 $setting->set_value($data->$name);
409 // Return the number of changes the user made
416 * Creates the backup_confirmation_form instance this stage requires
418 * @return backup_confirmation_form
420 protected function initialise_stage_form() {
422 if ($this->stageform === null) {
424 $form = new backup_confirmation_form($this, $PAGE->url);
426 $courseheading = false;
428 foreach ($this->ui->get_tasks() as $task) {
429 if ($setting = $task->get_setting('filename')) {
430 $form->add_heading('filenamesetting', get_string('filename', 'backup'));
431 if ($setting->get_value() == 'backup.mbz') {
432 $format = $this->ui->get_format();
433 $type = $this->ui->get_type();
434 $id = $this->ui->get_controller_id();
435 $users = $this->ui->get_setting_value('users');
436 $anonymised = $this->ui->get_setting_value('anonymize');
437 $setting->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
439 $form->add_setting($setting, $task);
444 // Track progress through tasks.
445 $progress = $this->ui->get_controller()->get_progress();
446 $tasks = $this->ui->get_tasks();
447 $progress->start_progress('initialise_stage_form', count($tasks));
450 foreach ($tasks as $task) {
451 if ($task instanceof backup_root_task) {
452 // If its a backup root add a root settings heading to group nicely
453 $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
454 } else if (!$courseheading) {
455 // we havn't already add a course heading
456 $form->add_heading('coursesettings', get_string('includeditems', 'backup'));
457 $courseheading = true;
459 // Iterate all settings, doesnt need to happen by reference
460 foreach ($task->get_settings() as $setting) {
461 // For this stage only the filename setting should be editable
462 if ($setting->get_name() != 'filename') {
463 $form->add_fixed_setting($setting, $task);
467 $progress->progress($done++);
469 $progress->end_progress();
470 $this->stageform = $form;
472 return $this->stageform;
477 * Final stage of backup
479 * This stage is special in that it is does not make use of a form. The reason for
480 * this is the order of procession of backup at this stage.
481 * The processesion is:
482 * 1. The final stage will be intialise.
483 * 2. The confirmation stage will be processed.
484 * 3. The backup will be executed
485 * 4. The complete stage will be loaded by execution
486 * 5. The complete stage will be displayed
488 * This highlights that we neither need a form nor a display method for this stage
489 * we simply need to process.
491 * @copyright 2010 Sam Hemelryk
492 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
494 class backup_ui_stage_final extends backup_ui_stage {
496 * Constructs the final stage
497 * @param backup_ui $ui
499 public function __construct(backup_ui $ui, array $params=null) {
500 $this->stage = backup_ui::STAGE_FINAL;
501 parent::__construct($ui, $params);
504 * Processes the final stage.
506 * In this case it ALWAYS passes processing to the previous stage (confirmation)
508 public function process(base_moodleform $form=null) {
512 * should NEVER be called... throws an exception
514 protected function initialise_stage_form() {
515 throw new backup_ui_exception('backup_ui_must_execute_first');
518 * should NEVER be called... throws an exception
520 public function display(core_backup_renderer $renderer) {
521 throw new backup_ui_exception('backup_ui_must_execute_first');
526 * The completed backup stage
528 * At this stage everything is done and the user will be redirected to view the
529 * backup file in the file browser.
531 * @copyright 2010 Sam Hemelryk
532 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
534 class backup_ui_stage_complete extends backup_ui_stage_final {
536 * The results of the backup execution
541 * Constructs the complete backup stage
542 * @param backup_ui $ui
543 * @param array|null $params
544 * @param array $results
546 public function __construct(backup_ui $ui, array $params=null, array $results=null) {
547 $this->results = $results;
548 parent::__construct($ui, $params);
549 $this->stage = backup_ui::STAGE_COMPLETE;
552 * Displays the completed backup stage.
554 * Currently this just involves redirecting to the file browser with an
555 * appropriate message.
557 * @param core_backup_renderer $renderer
558 * @return string HTML code to echo
560 public function display(core_backup_renderer $renderer) {
562 // Get the resulting stored_file record
563 $type = $this->get_ui()->get_controller()->get_type();
564 $courseid = $this->get_ui()->get_controller()->get_courseid();
567 $cmid = $this->get_ui()->get_controller()->get_id();
568 $cm = get_coursemodule_from_id(null, $cmid, $courseid);
569 $modcontext = context_module::instance($cm->id);
570 $restorerul = new moodle_url('/backup/restorefile.php', array('contextid'=>$modcontext->id));
574 $coursecontext = context_course::instance($courseid);
575 $restorerul = new moodle_url('/backup/restorefile.php', array('contextid'=>$coursecontext->id));
579 $output .= $renderer->box_start();
580 if (!empty($this->results['include_file_references_to_external_content'])) {
581 $output .= $renderer->notification(get_string('filereferencesincluded', 'backup'), 'notifyproblem');
583 if (!empty($this->results['missing_files_in_pool'])) {
584 $output .= $renderer->notification(get_string('missingfilesinpool', 'backup'), 'notifyproblem');
586 $output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
587 $output .= $renderer->continue_button($restorerul);
588 $output .= $renderer->box_end();