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 $form->collapse_heading('rootsettings');
179 $settings = $task->get_settings();
180 // First add all settings except the filename setting
181 foreach ($settings as &$setting) {
182 if ($setting->get_name() == 'filename') {
185 $add_settings[] = array($setting, $task);
187 // Then add all dependencies
188 foreach ($settings as &$setting) {
189 if ($setting->get_name() == 'filename') {
192 $dependencies[] = $setting;
196 // Add all settings at once.
197 $form->add_settings($add_settings);
199 foreach ($dependencies as $depsetting) {
200 $form->add_dependencies($depsetting);
202 $this->stageform = $form;
205 return $this->stageform;
210 * Schema stage of backup process
212 * During the schema stage the user is required to set the settings that relate
213 * to the area that they are backing up as well as its children.
215 * @copyright 2010 Sam Hemelryk
216 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
218 class backup_ui_stage_schema extends backup_ui_stage {
220 * @var int Maximum number of settings to add to form at once
222 const MAX_SETTINGS_BATCH = 1000;
225 * Schema stage constructor
226 * @param backup_moodleform $ui
228 public function __construct(backup_ui $ui, array $params=null) {
229 $this->stage = backup_ui::STAGE_SCHEMA;
230 parent::__construct($ui, $params);
233 * Processes the schema stage
235 * @param backup_moodleform|null $form
236 * @return int The number of changes the user made
238 public function process(base_moodleform $form = null) {
239 $form = $this->initialise_stage_form();
240 // Check it wasn't cancelled
241 if ($form->is_cancelled()) {
242 $this->ui->cancel_process();
245 // Check it has been submit
246 $data = $form->get_data();
247 if ($data && confirm_sesskey()) {
248 // Get the tasks into a var so we can iterate by reference
249 $tasks = $this->ui->get_tasks();
251 // Iterate all tasks by reference
252 foreach ($tasks as &$task) {
253 // We are only interested in schema settings
254 if (!($task instanceof backup_root_task)) {
255 // Store as a variable so we can iterate by reference
256 $settings = $task->get_settings();
257 // Iterate by reference
258 foreach ($settings as &$setting) {
259 $name = $setting->get_ui_name();
260 if (isset($data->$name) && $data->$name != $setting->get_value()) {
261 $setting->set_value($data->$name);
263 } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
264 $setting->set_value(0);
270 // Return the number of changes the user made
277 * Creates the backup_schema_form instance for this stage
279 * @return backup_schema_form
281 protected function initialise_stage_form() {
283 if ($this->stageform === null) {
284 $form = new backup_schema_form($this, $PAGE->url);
285 $tasks = $this->ui->get_tasks();
287 $courseheading = false;
288 $add_settings = array();
289 $dependencies = array();
291 // Track progress through each stage.
292 $progress = $this->ui->get_controller()->get_progress();
293 $progress->start_progress('Initialise stage form', 3);
295 // Get settings for all tasks.
296 $progress->start_progress('', count($tasks));
298 foreach ($tasks as $task) {
299 if (!($task instanceof backup_root_task)) {
300 if (!$courseheading) {
301 // If we havn't already display a course heading to group nicely
302 $form->add_heading('coursesettings', get_string('includeactivities', 'backup'));
303 $courseheading = true;
305 // First add each setting
306 foreach ($task->get_settings() as $setting) {
307 $add_settings[] = array($setting, $task);
309 // The add all the dependencies
310 foreach ($task->get_settings() as $setting) {
311 $dependencies[] = $setting;
313 } else if ($this->ui->enforce_changed_dependencies()) {
314 // Only show these settings if dependencies changed them.
315 // Add a root settings heading to group nicely
316 $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
317 // Iterate all settings and add them to the form as a fixed
318 // setting. We only want schema settings to be editable
319 foreach ($task->get_settings() as $setting) {
320 if ($setting->get_name() != 'filename') {
321 $form->add_fixed_setting($setting, $task);
326 $progress->progress($done++);
328 $progress->end_progress();
330 // Add settings for tasks in batches of up to 1000. Adding settings
331 // in larger batches improves performance, but if it takes too long,
332 // we won't be able to update the progress bar so the backup might
333 // time out. 1000 is chosen to balance this.
334 $numsettings = count($add_settings);
335 $progress->start_progress('', ceil($numsettings / self::MAX_SETTINGS_BATCH));
338 while($start < $numsettings) {
339 $length = min(self::MAX_SETTINGS_BATCH, $numsettings - $start);
340 $form->add_settings(array_slice($add_settings, $start, $length));
342 $progress->progress($done++);
344 $progress->end_progress();
346 $progress->start_progress('', count($dependencies));
348 foreach ($dependencies as $depsetting) {
349 $form->add_dependencies($depsetting);
350 $progress->progress($done++);
352 $progress->end_progress();
354 // End overall progress through creating form.
355 $progress->end_progress();
356 $this->stageform = $form;
358 return $this->stageform;
365 * On this stage the user reviews the setting for the backup and can change the filename
366 * of the file that will be generated.
368 * @copyright 2010 Sam Hemelryk
369 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
371 class backup_ui_stage_confirmation extends backup_ui_stage {
373 * Constructs the stage
374 * @param backup_ui $ui
376 public function __construct($ui, array $params=null) {
377 $this->stage = backup_ui::STAGE_CONFIRMATION;
378 parent::__construct($ui, $params);
381 * Processes the confirmation stage
383 * @param backup_moodleform $form
384 * @return int The number of changes the user made
386 public function process(base_moodleform $form = null) {
387 $form = $this->initialise_stage_form();
388 // Check it hasn't been cancelled
389 if ($form->is_cancelled()) {
390 $this->ui->cancel_process();
393 $data = $form->get_data();
394 if ($data && confirm_sesskey()) {
395 // Collect into a variable so we can iterate by reference
396 $tasks = $this->ui->get_tasks();
398 // Iterate each task by reference
399 foreach ($tasks as &$task) {
400 if ($task instanceof backup_root_task) {
401 // At this stage all we are interested in is the filename setting
402 $setting = $task->get_setting('filename');
403 $name = $setting->get_ui_name();
404 if (isset($data->$name) && $data->$name != $setting->get_value()) {
405 $setting->set_value($data->$name);
410 // Return the number of changes the user made
417 * Creates the backup_confirmation_form instance this stage requires
419 * @return backup_confirmation_form
421 protected function initialise_stage_form() {
423 if ($this->stageform === null) {
425 $form = new backup_confirmation_form($this, $PAGE->url);
427 $courseheading = false;
429 foreach ($this->ui->get_tasks() as $task) {
430 if ($setting = $task->get_setting('filename')) {
431 $form->add_heading('filenamesetting', get_string('filename', 'backup'));
432 if ($setting->get_value() == 'backup.mbz') {
433 $format = $this->ui->get_format();
434 $type = $this->ui->get_type();
435 $id = $this->ui->get_controller_id();
436 $users = $this->ui->get_setting_value('users');
437 $anonymised = $this->ui->get_setting_value('anonymize');
438 $setting->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
440 $form->add_setting($setting, $task);
445 // Track progress through tasks.
446 $progress = $this->ui->get_controller()->get_progress();
447 $tasks = $this->ui->get_tasks();
448 $progress->start_progress('initialise_stage_form', count($tasks));
451 foreach ($tasks as $task) {
452 if ($task instanceof backup_root_task) {
453 // If its a backup root add a root settings heading to group nicely
454 $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
455 } else if (!$courseheading) {
456 // we havn't already add a course heading
457 $form->add_heading('coursesettings', get_string('includeditems', 'backup'));
458 $courseheading = true;
460 // Iterate all settings, doesnt need to happen by reference
461 foreach ($task->get_settings() as $setting) {
462 // For this stage only the filename setting should be editable
463 if ($setting->get_name() != 'filename') {
464 $form->add_fixed_setting($setting, $task);
468 $progress->progress($done++);
470 $progress->end_progress();
471 $this->stageform = $form;
473 return $this->stageform;
478 * Final stage of backup
480 * This stage is special in that it is does not make use of a form. The reason for
481 * this is the order of procession of backup at this stage.
482 * The processesion is:
483 * 1. The final stage will be intialise.
484 * 2. The confirmation stage will be processed.
485 * 3. The backup will be executed
486 * 4. The complete stage will be loaded by execution
487 * 5. The complete stage will be displayed
489 * This highlights that we neither need a form nor a display method for this stage
490 * we simply need to process.
492 * @copyright 2010 Sam Hemelryk
493 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
495 class backup_ui_stage_final extends backup_ui_stage {
497 * Constructs the final stage
498 * @param backup_ui $ui
500 public function __construct(backup_ui $ui, array $params=null) {
501 $this->stage = backup_ui::STAGE_FINAL;
502 parent::__construct($ui, $params);
505 * Processes the final stage.
507 * In this case it ALWAYS passes processing to the previous stage (confirmation)
509 public function process(base_moodleform $form=null) {
513 * should NEVER be called... throws an exception
515 protected function initialise_stage_form() {
516 throw new backup_ui_exception('backup_ui_must_execute_first');
519 * should NEVER be called... throws an exception
521 public function display(core_backup_renderer $renderer) {
522 throw new backup_ui_exception('backup_ui_must_execute_first');
527 * The completed backup stage
529 * At this stage everything is done and the user will be redirected to view the
530 * backup file in the file browser.
532 * @copyright 2010 Sam Hemelryk
533 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
535 class backup_ui_stage_complete extends backup_ui_stage_final {
537 * The results of the backup execution
542 * Constructs the complete backup stage
543 * @param backup_ui $ui
544 * @param array|null $params
545 * @param array $results
547 public function __construct(backup_ui $ui, array $params=null, array $results=null) {
548 $this->results = $results;
549 parent::__construct($ui, $params);
550 $this->stage = backup_ui::STAGE_COMPLETE;
553 * Displays the completed backup stage.
555 * Currently this just involves redirecting to the file browser with an
556 * appropriate message.
558 * @param core_backup_renderer $renderer
559 * @return string HTML code to echo
561 public function display(core_backup_renderer $renderer) {
563 // Get the resulting stored_file record
564 $type = $this->get_ui()->get_controller()->get_type();
565 $courseid = $this->get_ui()->get_controller()->get_courseid();
568 $cmid = $this->get_ui()->get_controller()->get_id();
569 $cm = get_coursemodule_from_id(null, $cmid, $courseid);
570 $modcontext = context_module::instance($cm->id);
571 $restorerul = new moodle_url('/backup/restorefile.php', array('contextid'=>$modcontext->id));
575 $coursecontext = context_course::instance($courseid);
576 $restorerul = new moodle_url('/backup/restorefile.php', array('contextid'=>$coursecontext->id));
580 $output .= $renderer->box_start();
581 if (!empty($this->results['include_file_references_to_external_content'])) {
582 $output .= $renderer->notification(get_string('filereferencesincluded', 'backup'), 'notifyproblem');
584 if (!empty($this->results['missing_files_in_pool'])) {
585 $output .= $renderer->notification(get_string('missingfilesinpool', 'backup'), 'notifyproblem');
587 $output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
588 $output .= $renderer->continue_button($restorerul);
589 $output .= $renderer->box_end();