MDL-31443 backup: Title and cancel messages stating import and restore
[moodle.git] / backup / util / ui / backup_ui_stage.class.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Backup user interface stages
19  *
20  * This file contains the classes required to manage the stages that make up the
21  * backup user interface.
22  * These will be primarily operated a {@link backup_ui} instance.
23  *
24  * @package   core_backup
25  * @copyright 2010 Sam Hemelryk
26  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27  */
29 /**
30  * Abstract stage class
31  *
32  * This class should be extended by all backup stages (a requirement of many backup ui functions).
33  * Each stage must then define two abstract methods
34  *  - process : To process the stage
35  *  - initialise_stage_form : To get a backup_moodleform instance for the stage
36  *
37  * @package   core_backup
38  * @copyright 2010 Sam Hemelryk
39  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40  */
41 abstract class backup_ui_stage extends base_ui_stage {
43     /**
44      * Constructor.
45      *
46      * @param backup_ui $ui
47      * @param array $params
48      */
49     public function __construct(backup_ui $ui, array $params = null) {
50         parent::__construct($ui, $params);
51     }
53     /**
54      * The backup id from the backup controller
55      * @return string
56      */
57     final public function get_backupid() {
58         return $this->get_uniqueid();
59     }
60 }
62 /**
63  * Class representing the initial stage of a backup.
64  *
65  * In this stage the user is required to set the root level settings.
66  *
67  * @package   core_backup
68  * @copyright 2010 Sam Hemelryk
69  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
70  */
71 class backup_ui_stage_initial extends backup_ui_stage {
73     /**
74      * When set to true we skip all stages and jump to immediately processing the backup.
75      * @var bool
76      */
77     protected $oneclickbackup = false;
79     /**
80      * Initial backup stage constructor
81      * @param backup_ui $ui
82      * @param array $params
83      */
84     public function __construct(backup_ui $ui, array $params = null) {
85         $this->stage = backup_ui::STAGE_INITIAL;
86         parent::__construct($ui, $params);
87     }
89     /**
90      * Processes the initial backup stage
91      * @param base_moodleform $m
92      * @return int The number of changes
93      */
94     public function process(base_moodleform $m = null) {
96         $form = $this->initialise_stage_form();
98         if ($form->is_cancelled()) {
99             $this->ui->cancel_process();
100         }
102         $data = $form->get_data();
103         if ($data && confirm_sesskey()) {
104             if (isset($data->oneclickbackup)) {
105                 $this->oneclickbackup = true;
106             }
107             $tasks = $this->ui->get_tasks();
108             $changes = 0;
109             foreach ($tasks as &$task) {
110                 // We are only interesting in the backup root task for this stage.
111                 if ($task instanceof backup_root_task) {
112                     // Get all settings into a var so we can iterate by reference.
113                     $settings = $task->get_settings();
114                     foreach ($settings as &$setting) {
115                         $name = $setting->get_ui_name();
116                         if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
117                             $setting->set_value($data->$name);
118                             $changes++;
119                         } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
120                             $setting->set_value(0);
121                             $changes++;
122                         }
123                     }
124                 }
125             }
126             // Return the number of changes the user made.
127             return $changes;
128         } else {
129             return false;
130         }
131     }
133     /**
134      * Gets the next stage for the backup.
135      *
136      * We override this function to implement the one click backup.
137      * When the user performs a one click backup we jump straight to the final stage.
138      *
139      * @return int
140      */
141     public function get_next_stage() {
142         if ($this->oneclickbackup) {
143             // Its a one click backup.
144             // The default filename is backup.mbz, this normally gets set to something useful in the confirmation stage.
145             // because we skipped that stage we must manually set this to a useful value.
146             $tasks = $this->ui->get_tasks();
147             foreach ($tasks as $task) {
148                 if ($task instanceof backup_root_task) {
149                     // Find the filename setting.
150                     $setting = $task->get_setting('filename');
151                     if ($setting) {
152                         // Use the helper objects to get a useful name.
153                         $filename = backup_plan_dbops::get_default_backup_filename(
154                             $this->ui->get_format(),
155                             $this->ui->get_type(),
156                             $this->ui->get_controller_id(),
157                             $this->ui->get_setting_value('users'),
158                             $this->ui->get_setting_value('anonymize')
159                         );
160                         $setting->set_value($filename);
161                     }
162                 }
163             }
164             return backup_ui::STAGE_FINAL;
165         }
166         return parent::get_next_stage();
167     }
169     /**
170      * Initialises the backup_moodleform instance for this stage
171      *
172      * @return backup_initial_form
173      */
174     protected function initialise_stage_form() {
175         global $PAGE;
176         if ($this->stageform === null) {
177             $form = new backup_initial_form($this, $PAGE->url);
178             // Store as a variable so we can iterate by reference.
179             $tasks = $this->ui->get_tasks();
180             // Iterate all tasks by reference.
181             $add_settings = array();
182             $dependencies = array();
183             foreach ($tasks as &$task) {
184                 // For the initial stage we are only interested in the root settings.
185                 if ($task instanceof backup_root_task) {
186                     if ($this->ui instanceof import_ui) {
187                         $form->add_heading('rootsettings', get_string('importrootsettings', 'backup'));
188                     } else {
189                         $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
190                     }
191                     $settings = $task->get_settings();
192                     // First add all settings except the filename setting.
193                     foreach ($settings as &$setting) {
194                         if ($setting->get_name() == 'filename') {
195                             continue;
196                         }
197                         $add_settings[] = array($setting, $task);
198                     }
199                     // Then add all dependencies.
200                     foreach ($settings as &$setting) {
201                         if ($setting->get_name() == 'filename') {
202                             continue;
203                         }
204                         $dependencies[] = $setting;
205                     }
206                 }
207             }
208             // Add all settings at once.
209             $form->add_settings($add_settings);
210             // Add dependencies.
211             foreach ($dependencies as $depsetting) {
212                 $form->add_dependencies($depsetting);
213             }
214             $this->stageform = $form;
215         }
216         // Return the form.
217         return $this->stageform;
218     }
221 /**
222  * Schema stage of backup process
223  *
224  * During the schema stage the user is required to set the settings that relate
225  * to the area that they are backing up as well as its children.
226  *
227  * @package   core_backup
228  * @copyright 2010 Sam Hemelryk
229  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
230  */
231 class backup_ui_stage_schema extends backup_ui_stage {
233     /**
234      * @var int Maximum number of settings to add to form at once
235      */
236     const MAX_SETTINGS_BATCH = 1000;
238     /**
239      * Schema stage constructor
240      * @param backup_ui $ui
241      * @param array $params
242      */
243     public function __construct(backup_ui $ui, array $params = null) {
244         $this->stage = backup_ui::STAGE_SCHEMA;
245         parent::__construct($ui, $params);
246     }
248     /**
249      * Processes the schema stage
250      *
251      * @param base_moodleform $form
252      * @return int The number of changes the user made
253      */
254     public function process(base_moodleform $form = null) {
255         $form = $this->initialise_stage_form();
256         // Check it wasn't cancelled.
257         if ($form->is_cancelled()) {
258             $this->ui->cancel_process();
259         }
261         // Check it has been submit.
262         $data = $form->get_data();
263         if ($data && confirm_sesskey()) {
264             // Get the tasks into a var so we can iterate by reference.
265             $tasks = $this->ui->get_tasks();
266             $changes = 0;
267             // Iterate all tasks by reference.
268             foreach ($tasks as &$task) {
269                 // We are only interested in schema settings.
270                 if (!($task instanceof backup_root_task)) {
271                     // Store as a variable so we can iterate by reference.
272                     $settings = $task->get_settings();
273                     // Iterate by reference.
274                     foreach ($settings as &$setting) {
275                         $name = $setting->get_ui_name();
276                         if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
277                             $setting->set_value($data->$name);
278                             $changes++;
279                         } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
280                             $setting->set_value(0);
281                             $changes++;
282                         }
283                     }
284                 }
285             }
286             // Return the number of changes the user made.
287             return $changes;
288         } else {
289             return false;
290         }
291     }
293     /**
294      * Creates the backup_schema_form instance for this stage
295      *
296      * @return backup_schema_form
297      */
298     protected function initialise_stage_form() {
299         global $PAGE;
300         if ($this->stageform === null) {
301             $form = new backup_schema_form($this, $PAGE->url);
302             $tasks = $this->ui->get_tasks();
303             $content = '';
304             $courseheading = false;
305             $add_settings = array();
306             $dependencies = array();
308             // Track progress through each stage.
309             $progress = $this->ui->get_controller()->get_progress();
310             $progress->start_progress('Initialise stage form', 3);
312             // Get settings for all tasks.
313             $progress->start_progress('', count($tasks));
314             $done = 1;
315             foreach ($tasks as $task) {
316                 if (!($task instanceof backup_root_task)) {
317                     if (!$courseheading) {
318                         // If we haven't already display a course heading to group nicely.
319                         $form->add_heading('coursesettings', get_string('includeactivities', 'backup'));
320                         $courseheading = true;
321                     }
322                     // First add each setting.
323                     foreach ($task->get_settings() as $setting) {
324                         $add_settings[] = array($setting, $task);
325                     }
326                     // The add all the dependencies.
327                     foreach ($task->get_settings() as $setting) {
328                         $dependencies[] = $setting;
329                     }
330                 } else if ($this->ui->enforce_changed_dependencies()) {
331                     // Only show these settings if dependencies changed them.
332                     // Add a root settings heading to group nicely.
333                     $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
334                     // Iterate all settings and add them to the form as a fixed
335                     // setting. We only want schema settings to be editable.
336                     foreach ($task->get_settings() as $setting) {
337                         if ($setting->get_name() != 'filename') {
338                             $form->add_fixed_setting($setting, $task);
339                         }
340                     }
341                 }
342                 // Update progress.
343                 $progress->progress($done++);
344             }
345             $progress->end_progress();
347             // Add settings for tasks in batches of up to 1000. Adding settings
348             // in larger batches improves performance, but if it takes too long,
349             // we won't be able to update the progress bar so the backup might.
350             // time out. 1000 is chosen to balance this.
351             $numsettings = count($add_settings);
352             $progress->start_progress('', ceil($numsettings / self::MAX_SETTINGS_BATCH));
353             $start = 0;
354             $done = 1;
355             while ($start < $numsettings) {
356                 $length = min(self::MAX_SETTINGS_BATCH, $numsettings - $start);
357                 $form->add_settings(array_slice($add_settings, $start, $length));
358                 $start += $length;
359                 $progress->progress($done++);
360             }
361             $progress->end_progress();
363             $progress->start_progress('', count($dependencies));
364             $done = 1;
365             foreach ($dependencies as $depsetting) {
366                 $form->add_dependencies($depsetting);
367                 $progress->progress($done++);
368             }
369             $progress->end_progress();
371             // End overall progress through creating form.
372             $progress->end_progress();
373             $this->stageform = $form;
374         }
375         return $this->stageform;
376     }
379 /**
380  * Confirmation stage
381  *
382  * On this stage the user reviews the setting for the backup and can change the filename
383  * of the file that will be generated.
384  *
385  * @package   core_backup
386  * @copyright 2010 Sam Hemelryk
387  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
388  */
389 class backup_ui_stage_confirmation extends backup_ui_stage {
391     /**
392      * Constructs the stage
393      * @param backup_ui $ui
394      * @param array $params
395      */
396     public function __construct($ui, array $params = null) {
397         $this->stage = backup_ui::STAGE_CONFIRMATION;
398         parent::__construct($ui, $params);
399     }
401     /**
402      * Processes the confirmation stage
403      *
404      * @param base_moodleform $form
405      * @return int The number of changes the user made
406      */
407     public function process(base_moodleform $form = null) {
408         $form = $this->initialise_stage_form();
409         // Check it hasn't been cancelled.
410         if ($form->is_cancelled()) {
411             $this->ui->cancel_process();
412         }
414         $data = $form->get_data();
415         if ($data && confirm_sesskey()) {
416             // Collect into a variable so we can iterate by reference.
417             $tasks = $this->ui->get_tasks();
418             $changes = 0;
419             // Iterate each task by reference.
420             foreach ($tasks as &$task) {
421                 if ($task instanceof backup_root_task) {
422                     // At this stage all we are interested in is the filename setting.
423                     $setting = $task->get_setting('filename');
424                     $name = $setting->get_ui_name();
425                     if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
426                         $setting->set_value($data->$name);
427                         $changes++;
428                     }
429                 }
430             }
431             // Return the number of changes the user made.
432             return $changes;
433         } else {
434             return false;
435         }
436     }
438     /**
439      * Creates the backup_confirmation_form instance this stage requires
440      *
441      * @return backup_confirmation_form
442      */
443     protected function initialise_stage_form() {
444         global $PAGE;
445         if ($this->stageform === null) {
446             // Get the form.
447             $form = new backup_confirmation_form($this, $PAGE->url);
448             $content = '';
449             $courseheading = false;
451             foreach ($this->ui->get_tasks() as $task) {
452                 if ($setting = $task->get_setting('filename')) {
453                     $form->add_heading('filenamesetting', get_string('filename', 'backup'));
454                     if ($setting->get_value() == 'backup.mbz') {
455                         $format = $this->ui->get_format();
456                         $type = $this->ui->get_type();
457                         $id = $this->ui->get_controller_id();
458                         $users = $this->ui->get_setting_value('users');
459                         $anonymised = $this->ui->get_setting_value('anonymize');
460                         $setting->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
461                     }
462                     $form->add_setting($setting, $task);
463                     break;
464                 }
465             }
467             // Track progress through tasks.
468             $progress = $this->ui->get_controller()->get_progress();
469             $tasks = $this->ui->get_tasks();
470             $progress->start_progress('initialise_stage_form', count($tasks));
471             $done = 1;
473             foreach ($tasks as $task) {
474                 if ($task instanceof backup_root_task) {
475                     // If its a backup root add a root settings heading to group nicely.
476                     if ($this->ui instanceof import_ui) {
477                         $form->add_heading('rootsettings', get_string('importrootsettings', 'backup'));
478                     } else {
479                         $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
480                     }
481                 } else if (!$courseheading) {
482                     // We haven't already add a course heading.
483                     $form->add_heading('coursesettings', get_string('includeditems', 'backup'));
484                     $courseheading = true;
485                 }
486                 // Iterate all settings, doesnt need to happen by reference.
487                 foreach ($task->get_settings() as $setting) {
488                     // For this stage only the filename setting should be editable.
489                     if ($setting->get_name() != 'filename') {
490                         $form->add_fixed_setting($setting, $task);
491                     }
492                 }
493                 // Update progress.
494                 $progress->progress($done++);
495             }
496             $progress->end_progress();
497             $this->stageform = $form;
498         }
499         return $this->stageform;
500     }
503 /**
504  * Final stage of backup
505  *
506  * This stage is special in that it is does not make use of a form. The reason for
507  * this is the order of procession of backup at this stage.
508  * The processesion is:
509  * 1. The final stage will be intialise.
510  * 2. The confirmation stage will be processed.
511  * 3. The backup will be executed
512  * 4. The complete stage will be loaded by execution
513  * 5. The complete stage will be displayed
514  *
515  * This highlights that we neither need a form nor a display method for this stage
516  * we simply need to process.
517  *
518  * @package   core_backup
519  * @copyright 2010 Sam Hemelryk
520  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
521  */
522 class backup_ui_stage_final extends backup_ui_stage {
524     /**
525      * Constructs the final stage
526      * @param backup_ui $ui
527      * @param array $params
528      */
529     public function __construct(backup_ui $ui, array $params = null) {
530         $this->stage = backup_ui::STAGE_FINAL;
531         parent::__construct($ui, $params);
532     }
534     /**
535      * Processes the final stage.
536      *
537      * In this case it ALWAYS passes processing to the previous stage (confirmation)
538      *
539      * @param base_moodleform $form
540      * @return bool
541      */
542     public function process(base_moodleform $form = null) {
543         return true;
544     }
546     /**
547      * should NEVER be called... throws an exception
548      */
549     protected function initialise_stage_form() {
550         throw new backup_ui_exception('backup_ui_must_execute_first');
551     }
553     /**
554      * should NEVER be called... throws an exception
555      *
556      * @throws backup_ui_exception always
557      * @param core_backup_renderer $renderer
558      * @return void
559      */
560     public function display(core_backup_renderer $renderer) {
561         throw new backup_ui_exception('backup_ui_must_execute_first');
562     }
565 /**
566  * The completed backup stage
567  *
568  * At this stage everything is done and the user will be redirected to view the
569  * backup file in the file browser.
570  *
571  * @package   core_backup
572  * @copyright 2010 Sam Hemelryk
573  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
574  */
575 class backup_ui_stage_complete extends backup_ui_stage_final {
577     /**
578      * The results of the backup execution
579      * @var array
580      */
581     protected $results;
583     /**
584      * Constructs the complete backup stage
585      *
586      * @param backup_ui $ui
587      * @param array $params
588      * @param array $results
589      */
590     public function __construct(backup_ui $ui, array $params = null, array $results = null) {
591         $this->results = $results;
592         parent::__construct($ui, $params);
593         $this->stage = backup_ui::STAGE_COMPLETE;
594     }
596     /**
597      * Displays the completed backup stage.
598      *
599      * Currently this just involves redirecting to the file browser with an
600      * appropriate message.
601      *
602      * @param core_backup_renderer $renderer
603      * @return string HTML code to echo
604      */
605     public function display(core_backup_renderer $renderer) {
607         // Get the resulting stored_file record.
608         $type = $this->get_ui()->get_controller()->get_type();
609         $courseid = $this->get_ui()->get_controller()->get_courseid();
610         switch ($type) {
611             case 'activity':
612                 $cmid = $this->get_ui()->get_controller()->get_id();
613                 $cm = get_coursemodule_from_id(null, $cmid, $courseid);
614                 $modcontext = context_module::instance($cm->id);
615                 $restorerul = new moodle_url('/backup/restorefile.php', array('contextid' => $modcontext->id));
616                 break;
617             case 'course':
618             default:
619                 $coursecontext = context_course::instance($courseid);
620                 $restorerul = new moodle_url('/backup/restorefile.php', array('contextid' => $coursecontext->id));
621         }
623         $output = '';
624         $output .= $renderer->box_start();
625         if (!empty($this->results['include_file_references_to_external_content'])) {
626             $output .= $renderer->notification(get_string('filereferencesincluded', 'backup'), 'notifyproblem');
627         }
628         if (!empty($this->results['missing_files_in_pool'])) {
629             $output .= $renderer->notification(get_string('missingfilesinpool', 'backup'), 'notifyproblem');
630         }
631         $output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
632         $output .= $renderer->continue_button($restorerul);
633         $output .= $renderer->box_end();
635         return $output;
636     }