257a2ec10d618ab7e739092a251c556fbe253748
[moodle.git] / backup / util / ui / backup_ui_stage.class.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
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.
9 //
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.
14 //
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/>.
18 /**
19  * Backup user interface stages
20  *
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.
24  *
25  * @package   moodlecore
26  * @copyright 2010 Sam Hemelryk
27  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28  */
30 /**
31  * Abstract stage class
32  *
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
37  *
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     public function __construct(backup_ui $ui, array $params = null) {
44        parent::__construct($ui, $params);
45     }
46     /**
47      * The backup id from the backup controller
48      * @return string
49      */
50     final public function get_backupid() {
51         return $this->get_uniqueid();
52     }
53 }
55 /**
56  * Class representing the initial stage of a backup.
57  *
58  * In this stage the user is required to set the root level settings.
59  *
60  * @copyright 2010 Sam Hemelryk
61  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
62  */
63 class backup_ui_stage_initial extends backup_ui_stage {
65     /**
66      * Initial backup stage constructor
67      * @param backup_ui $ui
68      */
69     public function __construct(backup_ui $ui, array $params=null) {
70         $this->stage = backup_ui::STAGE_INITIAL;
71         parent::__construct($ui, $params);
72     }
74     /**
75      * Processes the initial backup stage
76      * @param backup_moodleform $form
77      * @return int The number of changes
78      */
79     public function process(base_moodleform $m = null) {
81         $form = $this->initialise_stage_form();
83         if ($form->is_cancelled()) {
84             $this->ui->cancel_process();
85         }
87         $data = $form->get_data();
88         if ($data && confirm_sesskey()) {
89             $tasks = $this->ui->get_tasks();
90             $changes = 0;
91             foreach ($tasks as &$task) {
92                 // We are only interesting in the backup root task for this stage
93                 if ($task instanceof backup_root_task) {
94                     // Get all settings into a var so we can iterate by reference
95                     $settings = $task->get_settings();
96                     foreach ($settings as &$setting) {
97                         $name = $setting->get_ui_name();
98                         if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
99                             $setting->set_value($data->$name);
100                             $changes++;
101                         } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
102                             $setting->set_value(0);
103                             $changes++;
104                         }
105                     }
106                 }
107             }
108             // Return the number of changes the user made
109             return $changes;
110         } else {
111             return false;
112         }
113     }
115     /**
116      * Initialises the backup_moodleform instance for this stage
117      *
118      * @return backup_initial_form
119      */
120     protected function initialise_stage_form() {
121         global $PAGE;
122         if ($this->stageform === null) {
123             $form = new backup_initial_form($this, $PAGE->url);
124             // Store as a variable so we can iterate by reference
125             $tasks = $this->ui->get_tasks();
126             // Iterate all tasks by reference
127             $add_settings = array();
128             $dependencies = array();
129             foreach ($tasks as &$task) {
130                 // For the initial stage we are only interested in the root settings
131                 if ($task instanceof backup_root_task) {
132                     $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
133                     $settings = $task->get_settings();
134                     // First add all settings except the filename setting
135                     foreach ($settings as &$setting) {
136                         if ($setting->get_name() == 'filename') {
137                             continue;
138                         }
139                         $add_settings[] = array($setting, $task);
140                     }
141                     // Then add all dependencies
142                     foreach ($settings as &$setting) {
143                         if ($setting->get_name() == 'filename') {
144                             continue;
145                         }
146                         $dependencies[] = $setting;
147                     }
148                 }
149             }
150             // Add all settings at once.
151             $form->add_settings($add_settings);
152             // Add dependencies.
153             foreach ($dependencies as $depsetting) {
154                 $form->add_dependencies($depsetting);
155             }
156             $this->stageform = $form;
157         }
158         // Return the form
159         return $this->stageform;
160     }
163 /**
164  * Schema stage of backup process
165  *
166  * During the schema stage the user is required to set the settings that relate
167  * to the area that they are backing up as well as its children.
168  *
169  * @copyright 2010 Sam Hemelryk
170  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
171  */
172 class backup_ui_stage_schema extends backup_ui_stage {
173     /**
174      * @var int Maximum number of settings to add to form at once
175      */
176     const MAX_SETTINGS_BATCH = 1000;
178     /**
179      * Schema stage constructor
180      * @param backup_moodleform $ui
181      */
182     public function __construct(backup_ui $ui, array $params=null) {
183         $this->stage = backup_ui::STAGE_SCHEMA;
184         parent::__construct($ui, $params);
185     }
186     /**
187      * Processes the schema stage
188      *
189      * @param backup_moodleform|null $form
190      * @return int The number of changes the user made
191      */
192     public function process(base_moodleform $form = null) {
193         $form = $this->initialise_stage_form();
194         // Check it wasn't cancelled
195         if ($form->is_cancelled()) {
196             $this->ui->cancel_process();
197         }
199         // Check it has been submit
200         $data = $form->get_data();
201         if ($data && confirm_sesskey()) {
202             // Get the tasks into a var so we can iterate by reference
203             $tasks = $this->ui->get_tasks();
204             $changes = 0;
205             // Iterate all tasks by reference
206             foreach ($tasks as &$task) {
207                 // We are only interested in schema settings
208                 if (!($task instanceof backup_root_task)) {
209                     // Store as a variable so we can iterate by reference
210                     $settings = $task->get_settings();
211                     // Iterate by reference
212                     foreach ($settings as &$setting) {
213                         $name = $setting->get_ui_name();
214                         if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
215                             $setting->set_value($data->$name);
216                             $changes++;
217                         } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
218                             $setting->set_value(0);
219                             $changes++;
220                         }
221                     }
222                 }
223             }
224             // Return the number of changes the user made
225             return $changes;
226         } else {
227             return false;
228         }
229     }
230     /**
231      * Creates the backup_schema_form instance for this stage
232      *
233      * @return backup_schema_form
234      */
235     protected function initialise_stage_form() {
236         global $PAGE;
237         if ($this->stageform === null) {
238             $form = new backup_schema_form($this, $PAGE->url);
239             $tasks = $this->ui->get_tasks();
240             $content = '';
241             $courseheading = false;
242             $add_settings = array();
243             $dependencies = array();
245             // Track progress through each stage.
246             $progress = $this->ui->get_controller()->get_progress();
247             $progress->start_progress('Initialise stage form', 3);
249             // Get settings for all tasks.
250             $progress->start_progress('', count($tasks));
251             $done = 1;
252             foreach ($tasks as $task) {
253                 if (!($task instanceof backup_root_task)) {
254                     if (!$courseheading) {
255                         // If we havn't already display a course heading to group nicely
256                         $form->add_heading('coursesettings', get_string('includeactivities', 'backup'));
257                         $courseheading = true;
258                     }
259                     // First add each setting
260                     foreach ($task->get_settings() as $setting) {
261                         $add_settings[] = array($setting, $task);
262                     }
263                     // The add all the dependencies
264                     foreach ($task->get_settings() as $setting) {
265                         $dependencies[] = $setting;
266                     }
267                 } else if ($this->ui->enforce_changed_dependencies()) {
268                     // Only show these settings if dependencies changed them.
269                     // Add a root settings heading to group nicely
270                     $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
271                     // Iterate all settings and add them to the form as a fixed
272                     // setting. We only want schema settings to be editable
273                     foreach ($task->get_settings() as $setting) {
274                         if ($setting->get_name() != 'filename') {
275                             $form->add_fixed_setting($setting, $task);
276                         }
277                     }
278                 }
279                 // Update progress.
280                 $progress->progress($done++);
281             }
282             $progress->end_progress();
284             // Add settings for tasks in batches of up to 1000. Adding settings
285             // in larger batches improves performance, but if it takes too long,
286             // we won't be able to update the progress bar so the backup might
287             // time out. 1000 is chosen to balance this.
288             $numsettings = count($add_settings);
289             $progress->start_progress('', ceil($numsettings / self::MAX_SETTINGS_BATCH));
290             $start = 0;
291             $done = 1;
292             while($start < $numsettings) {
293                 $length = min(self::MAX_SETTINGS_BATCH, $numsettings - $start);
294                 $form->add_settings(array_slice($add_settings, $start, $length));
295                 $start += $length;
296                 $progress->progress($done++);
297             }
298             $progress->end_progress();
300             $progress->start_progress('', count($dependencies));
301             $done = 1;
302             foreach ($dependencies as $depsetting) {
303                 $form->add_dependencies($depsetting);
304                 $progress->progress($done++);
305             }
306             $progress->end_progress();
308             // End overall progress through creating form.
309             $progress->end_progress();
310             $this->stageform = $form;
311         }
312         return $this->stageform;
313     }
316 /**
317  * Confirmation stage
318  *
319  * On this stage the user reviews the setting for the backup and can change the filename
320  * of the file that will be generated.
321  *
322  * @copyright 2010 Sam Hemelryk
323  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
324  */
325 class backup_ui_stage_confirmation extends backup_ui_stage {
326     /**
327      * Constructs the stage
328      * @param backup_ui $ui
329      */
330     public function __construct($ui, array $params=null) {
331         $this->stage = backup_ui::STAGE_CONFIRMATION;
332         parent::__construct($ui, $params);
333     }
334     /**
335      * Processes the confirmation stage
336      *
337      * @param backup_moodleform $form
338      * @return int The number of changes the user made
339      */
340     public function process(base_moodleform $form = null) {
341         $form = $this->initialise_stage_form();
342         // Check it hasn't been cancelled
343         if ($form->is_cancelled()) {
344             $this->ui->cancel_process();
345         }
347         $data = $form->get_data();
348         if ($data && confirm_sesskey()) {
349             // Collect into a variable so we can iterate by reference
350             $tasks = $this->ui->get_tasks();
351             $changes = 0;
352             // Iterate each task by reference
353             foreach ($tasks as &$task) {
354                 if ($task instanceof backup_root_task) {
355                     // At this stage all we are interested in is the filename setting
356                     $setting = $task->get_setting('filename');
357                     $name = $setting->get_ui_name();
358                     if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
359                         $setting->set_value($data->$name);
360                         $changes++;
361                     }
362                 }
363             }
364             // Return the number of changes the user made
365             return $changes;
366         } else {
367             return false;
368         }
369     }
370     /**
371      * Creates the backup_confirmation_form instance this stage requires
372      *
373      * @return backup_confirmation_form
374      */
375     protected function initialise_stage_form() {
376         global $PAGE;
377         if ($this->stageform === null) {
378             // Get the form
379             $form = new backup_confirmation_form($this, $PAGE->url);
380             $content = '';
381             $courseheading = false;
383             foreach ($this->ui->get_tasks() as $task) {
384                 if ($setting = $task->get_setting('filename')) {
385                     $form->add_heading('filenamesetting', get_string('filename', 'backup'));
386                     if ($setting->get_value() == 'backup.mbz') {
387                         $format = $this->ui->get_format();
388                         $type = $this->ui->get_type();
389                         $id = $this->ui->get_controller_id();
390                         $users = $this->ui->get_setting_value('users');
391                         $anonymised = $this->ui->get_setting_value('anonymize');
392                         $setting->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
393                     }
394                     $form->add_setting($setting, $task);
395                     break;
396                 }
397             }
399             // Track progress through tasks.
400             $progress = $this->ui->get_controller()->get_progress();
401             $tasks = $this->ui->get_tasks();
402             $progress->start_progress('initialise_stage_form', count($tasks));
403             $done = 1;
405             foreach ($tasks as $task) {
406                 if ($task instanceof backup_root_task) {
407                     // If its a backup root add a root settings heading to group nicely
408                     $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
409                 } else if (!$courseheading) {
410                     // we havn't already add a course heading
411                     $form->add_heading('coursesettings', get_string('includeditems', 'backup'));
412                     $courseheading = true;
413                 }
414                 // Iterate all settings, doesnt need to happen by reference
415                 foreach ($task->get_settings() as $setting) {
416                     // For this stage only the filename setting should be editable
417                     if ($setting->get_name() != 'filename') {
418                         $form->add_fixed_setting($setting, $task);
419                     }
420                 }
421                 // Update progress.
422                 $progress->progress($done++);
423             }
424             $progress->end_progress();
425             $this->stageform = $form;
426         }
427         return $this->stageform;
428     }
431 /**
432  * Final stage of backup
433  *
434  * This stage is special in that it is does not make use of a form. The reason for
435  * this is the order of procession of backup at this stage.
436  * The processesion is:
437  * 1. The final stage will be intialise.
438  * 2. The confirmation stage will be processed.
439  * 3. The backup will be executed
440  * 4. The complete stage will be loaded by execution
441  * 5. The complete stage will be displayed
442  *
443  * This highlights that we neither need a form nor a display method for this stage
444  * we simply need to process.
445  *
446  * @copyright 2010 Sam Hemelryk
447  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
448  */
449 class backup_ui_stage_final extends backup_ui_stage {
450     /**
451      * Constructs the final stage
452      * @param backup_ui $ui
453      */
454     public function __construct(backup_ui $ui, array $params=null) {
455         $this->stage = backup_ui::STAGE_FINAL;
456         parent::__construct($ui, $params);
457     }
458     /**
459      * Processes the final stage.
460      *
461      * In this case it ALWAYS passes processing to the previous stage (confirmation)
462      */
463     public function process(base_moodleform $form=null) {
464         return true;
465     }
466     /**
467      * should NEVER be called... throws an exception
468      */
469     protected function initialise_stage_form() {
470         throw new backup_ui_exception('backup_ui_must_execute_first');
471     }
472     /**
473      * should NEVER be called... throws an exception
474      */
475     public function display(core_backup_renderer $renderer) {
476         throw new backup_ui_exception('backup_ui_must_execute_first');
477     }
480 /**
481  * The completed backup stage
482  *
483  * At this stage everything is done and the user will be redirected to view the
484  * backup file in the file browser.
485  *
486  * @copyright 2010 Sam Hemelryk
487  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
488  */
489 class backup_ui_stage_complete extends backup_ui_stage_final {
490     /**
491      * The results of the backup execution
492      * @var array
493      */
494     protected $results;
495     /**
496      * Constructs the complete backup stage
497      * @param backup_ui $ui
498      * @param array|null $params
499      * @param array $results
500      */
501     public function __construct(backup_ui $ui, array $params=null, array $results=null) {
502         $this->results = $results;
503         parent::__construct($ui, $params);
504         $this->stage = backup_ui::STAGE_COMPLETE;
505     }
506     /**
507      * Displays the completed backup stage.
508      *
509      * Currently this just involves redirecting to the file browser with an
510      * appropriate message.
511      *
512      * @param core_backup_renderer $renderer
513      * @return string HTML code to echo
514      */
515     public function display(core_backup_renderer $renderer) {
517         // Get the resulting stored_file record
518         $type = $this->get_ui()->get_controller()->get_type();
519         $courseid = $this->get_ui()->get_controller()->get_courseid();
520         switch ($type) {
521         case 'activity':
522             $cmid = $this->get_ui()->get_controller()->get_id();
523             $cm = get_coursemodule_from_id(null, $cmid, $courseid);
524             $modcontext = context_module::instance($cm->id);
525             $restorerul = new moodle_url('/backup/restorefile.php', array('contextid'=>$modcontext->id));
526             break;
527         case 'course':
528         default:
529             $coursecontext = context_course::instance($courseid);
530             $restorerul = new moodle_url('/backup/restorefile.php', array('contextid'=>$coursecontext->id));
531         }
533         $output = '';
534         $output .= $renderer->box_start();
535         if (!empty($this->results['include_file_references_to_external_content'])) {
536             $output .= $renderer->notification(get_string('filereferencesincluded', 'backup'), 'notifyproblem');
537         }
538         if (!empty($this->results['missing_files_in_pool'])) {
539             $output .= $renderer->notification(get_string('missingfilesinpool', 'backup'), 'notifyproblem');
540         }
541         $output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
542         $output .= $renderer->continue_button($restorerul);
543         $output .= $renderer->box_end();
545         return $output;
546     }