Merge branch 'MDL-22309_master' of git://github.com/dmonllao/moodle
[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                     $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
187                     $settings = $task->get_settings();
188                     // First add all settings except the filename setting.
189                     foreach ($settings as &$setting) {
190                         if ($setting->get_name() == 'filename') {
191                             continue;
192                         }
193                         $add_settings[] = array($setting, $task);
194                     }
195                     // Then add all dependencies.
196                     foreach ($settings as &$setting) {
197                         if ($setting->get_name() == 'filename') {
198                             continue;
199                         }
200                         $dependencies[] = $setting;
201                     }
202                 }
203             }
204             // Add all settings at once.
205             $form->add_settings($add_settings);
206             // Add dependencies.
207             foreach ($dependencies as $depsetting) {
208                 $form->add_dependencies($depsetting);
209             }
210             $this->stageform = $form;
211         }
212         // Return the form.
213         return $this->stageform;
214     }
217 /**
218  * Schema stage of backup process
219  *
220  * During the schema stage the user is required to set the settings that relate
221  * to the area that they are backing up as well as its children.
222  *
223  * @package   core_backup
224  * @copyright 2010 Sam Hemelryk
225  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
226  */
227 class backup_ui_stage_schema extends backup_ui_stage {
229     /**
230      * @var int Maximum number of settings to add to form at once
231      */
232     const MAX_SETTINGS_BATCH = 1000;
234     /**
235      * Schema stage constructor
236      * @param backup_ui $ui
237      * @param array $params
238      */
239     public function __construct(backup_ui $ui, array $params = null) {
240         $this->stage = backup_ui::STAGE_SCHEMA;
241         parent::__construct($ui, $params);
242     }
244     /**
245      * Processes the schema stage
246      *
247      * @param base_moodleform $form
248      * @return int The number of changes the user made
249      */
250     public function process(base_moodleform $form = null) {
251         $form = $this->initialise_stage_form();
252         // Check it wasn't cancelled.
253         if ($form->is_cancelled()) {
254             $this->ui->cancel_process();
255         }
257         // Check it has been submit.
258         $data = $form->get_data();
259         if ($data && confirm_sesskey()) {
260             // Get the tasks into a var so we can iterate by reference.
261             $tasks = $this->ui->get_tasks();
262             $changes = 0;
263             // Iterate all tasks by reference.
264             foreach ($tasks as &$task) {
265                 // We are only interested in schema settings.
266                 if (!($task instanceof backup_root_task)) {
267                     // Store as a variable so we can iterate by reference.
268                     $settings = $task->get_settings();
269                     // Iterate by reference.
270                     foreach ($settings as &$setting) {
271                         $name = $setting->get_ui_name();
272                         if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
273                             $setting->set_value($data->$name);
274                             $changes++;
275                         } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
276                             $setting->set_value(0);
277                             $changes++;
278                         }
279                     }
280                 }
281             }
282             // Return the number of changes the user made.
283             return $changes;
284         } else {
285             return false;
286         }
287     }
289     /**
290      * Creates the backup_schema_form instance for this stage
291      *
292      * @return backup_schema_form
293      */
294     protected function initialise_stage_form() {
295         global $PAGE;
296         if ($this->stageform === null) {
297             $form = new backup_schema_form($this, $PAGE->url);
298             $tasks = $this->ui->get_tasks();
299             $content = '';
300             $courseheading = false;
301             $add_settings = array();
302             $dependencies = array();
304             // Track progress through each stage.
305             $progress = $this->ui->get_controller()->get_progress();
306             $progress->start_progress('Initialise stage form', 3);
308             // Get settings for all tasks.
309             $progress->start_progress('', count($tasks));
310             $done = 1;
311             foreach ($tasks as $task) {
312                 if (!($task instanceof backup_root_task)) {
313                     if (!$courseheading) {
314                         // If we haven't already display a course heading to group nicely.
315                         $form->add_heading('coursesettings', get_string('includeactivities', 'backup'));
316                         $courseheading = true;
317                     }
318                     // First add each setting.
319                     foreach ($task->get_settings() as $setting) {
320                         $add_settings[] = array($setting, $task);
321                     }
322                     // The add all the dependencies.
323                     foreach ($task->get_settings() as $setting) {
324                         $dependencies[] = $setting;
325                     }
326                 } else if ($this->ui->enforce_changed_dependencies()) {
327                     // Only show these settings if dependencies changed them.
328                     // Add a root settings heading to group nicely.
329                     $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
330                     // Iterate all settings and add them to the form as a fixed
331                     // setting. We only want schema settings to be editable.
332                     foreach ($task->get_settings() as $setting) {
333                         if ($setting->get_name() != 'filename') {
334                             $form->add_fixed_setting($setting, $task);
335                         }
336                     }
337                 }
338                 // Update progress.
339                 $progress->progress($done++);
340             }
341             $progress->end_progress();
343             // Add settings for tasks in batches of up to 1000. Adding settings
344             // in larger batches improves performance, but if it takes too long,
345             // we won't be able to update the progress bar so the backup might.
346             // time out. 1000 is chosen to balance this.
347             $numsettings = count($add_settings);
348             $progress->start_progress('', ceil($numsettings / self::MAX_SETTINGS_BATCH));
349             $start = 0;
350             $done = 1;
351             while ($start < $numsettings) {
352                 $length = min(self::MAX_SETTINGS_BATCH, $numsettings - $start);
353                 $form->add_settings(array_slice($add_settings, $start, $length));
354                 $start += $length;
355                 $progress->progress($done++);
356             }
357             $progress->end_progress();
359             $progress->start_progress('', count($dependencies));
360             $done = 1;
361             foreach ($dependencies as $depsetting) {
362                 $form->add_dependencies($depsetting);
363                 $progress->progress($done++);
364             }
365             $progress->end_progress();
367             // End overall progress through creating form.
368             $progress->end_progress();
369             $this->stageform = $form;
370         }
371         return $this->stageform;
372     }
375 /**
376  * Confirmation stage
377  *
378  * On this stage the user reviews the setting for the backup and can change the filename
379  * of the file that will be generated.
380  *
381  * @package   core_backup
382  * @copyright 2010 Sam Hemelryk
383  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
384  */
385 class backup_ui_stage_confirmation extends backup_ui_stage {
387     /**
388      * Constructs the stage
389      * @param backup_ui $ui
390      * @param array $params
391      */
392     public function __construct($ui, array $params = null) {
393         $this->stage = backup_ui::STAGE_CONFIRMATION;
394         parent::__construct($ui, $params);
395     }
397     /**
398      * Processes the confirmation stage
399      *
400      * @param base_moodleform $form
401      * @return int The number of changes the user made
402      */
403     public function process(base_moodleform $form = null) {
404         $form = $this->initialise_stage_form();
405         // Check it hasn't been cancelled.
406         if ($form->is_cancelled()) {
407             $this->ui->cancel_process();
408         }
410         $data = $form->get_data();
411         if ($data && confirm_sesskey()) {
412             // Collect into a variable so we can iterate by reference.
413             $tasks = $this->ui->get_tasks();
414             $changes = 0;
415             // Iterate each task by reference.
416             foreach ($tasks as &$task) {
417                 if ($task instanceof backup_root_task) {
418                     // At this stage all we are interested in is the filename setting.
419                     $setting = $task->get_setting('filename');
420                     $name = $setting->get_ui_name();
421                     if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
422                         $setting->set_value($data->$name);
423                         $changes++;
424                     }
425                 }
426             }
427             // Return the number of changes the user made.
428             return $changes;
429         } else {
430             return false;
431         }
432     }
434     /**
435      * Creates the backup_confirmation_form instance this stage requires
436      *
437      * @return backup_confirmation_form
438      */
439     protected function initialise_stage_form() {
440         global $PAGE;
441         if ($this->stageform === null) {
442             // Get the form.
443             $form = new backup_confirmation_form($this, $PAGE->url);
444             $content = '';
445             $courseheading = false;
447             foreach ($this->ui->get_tasks() as $task) {
448                 if ($setting = $task->get_setting('filename')) {
449                     $form->add_heading('filenamesetting', get_string('filename', 'backup'));
450                     if ($setting->get_value() == 'backup.mbz') {
451                         $format = $this->ui->get_format();
452                         $type = $this->ui->get_type();
453                         $id = $this->ui->get_controller_id();
454                         $users = $this->ui->get_setting_value('users');
455                         $anonymised = $this->ui->get_setting_value('anonymize');
456                         $setting->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
457                     }
458                     $form->add_setting($setting, $task);
459                     break;
460                 }
461             }
463             // Track progress through tasks.
464             $progress = $this->ui->get_controller()->get_progress();
465             $tasks = $this->ui->get_tasks();
466             $progress->start_progress('initialise_stage_form', count($tasks));
467             $done = 1;
469             foreach ($tasks as $task) {
470                 if ($task instanceof backup_root_task) {
471                     // If its a backup root add a root settings heading to group nicely.
472                     $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
473                 } else if (!$courseheading) {
474                     // We haven't already add a course heading.
475                     $form->add_heading('coursesettings', get_string('includeditems', 'backup'));
476                     $courseheading = true;
477                 }
478                 // Iterate all settings, doesnt need to happen by reference.
479                 foreach ($task->get_settings() as $setting) {
480                     // For this stage only the filename setting should be editable.
481                     if ($setting->get_name() != 'filename') {
482                         $form->add_fixed_setting($setting, $task);
483                     }
484                 }
485                 // Update progress.
486                 $progress->progress($done++);
487             }
488             $progress->end_progress();
489             $this->stageform = $form;
490         }
491         return $this->stageform;
492     }
495 /**
496  * Final stage of backup
497  *
498  * This stage is special in that it is does not make use of a form. The reason for
499  * this is the order of procession of backup at this stage.
500  * The processesion is:
501  * 1. The final stage will be intialise.
502  * 2. The confirmation stage will be processed.
503  * 3. The backup will be executed
504  * 4. The complete stage will be loaded by execution
505  * 5. The complete stage will be displayed
506  *
507  * This highlights that we neither need a form nor a display method for this stage
508  * we simply need to process.
509  *
510  * @package   core_backup
511  * @copyright 2010 Sam Hemelryk
512  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
513  */
514 class backup_ui_stage_final extends backup_ui_stage {
516     /**
517      * Constructs the final stage
518      * @param backup_ui $ui
519      * @param array $params
520      */
521     public function __construct(backup_ui $ui, array $params = null) {
522         $this->stage = backup_ui::STAGE_FINAL;
523         parent::__construct($ui, $params);
524     }
526     /**
527      * Processes the final stage.
528      *
529      * In this case it ALWAYS passes processing to the previous stage (confirmation)
530      *
531      * @param base_moodleform $form
532      * @return bool
533      */
534     public function process(base_moodleform $form = null) {
535         return true;
536     }
538     /**
539      * should NEVER be called... throws an exception
540      */
541     protected function initialise_stage_form() {
542         throw new backup_ui_exception('backup_ui_must_execute_first');
543     }
545     /**
546      * should NEVER be called... throws an exception
547      *
548      * @throws backup_ui_exception always
549      * @param core_backup_renderer $renderer
550      * @return void
551      */
552     public function display(core_backup_renderer $renderer) {
553         throw new backup_ui_exception('backup_ui_must_execute_first');
554     }
557 /**
558  * The completed backup stage
559  *
560  * At this stage everything is done and the user will be redirected to view the
561  * backup file in the file browser.
562  *
563  * @package   core_backup
564  * @copyright 2010 Sam Hemelryk
565  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
566  */
567 class backup_ui_stage_complete extends backup_ui_stage_final {
569     /**
570      * The results of the backup execution
571      * @var array
572      */
573     protected $results;
575     /**
576      * Constructs the complete backup stage
577      *
578      * @param backup_ui $ui
579      * @param array $params
580      * @param array $results
581      */
582     public function __construct(backup_ui $ui, array $params = null, array $results = null) {
583         $this->results = $results;
584         parent::__construct($ui, $params);
585         $this->stage = backup_ui::STAGE_COMPLETE;
586     }
588     /**
589      * Displays the completed backup stage.
590      *
591      * Currently this just involves redirecting to the file browser with an
592      * appropriate message.
593      *
594      * @param core_backup_renderer $renderer
595      * @return string HTML code to echo
596      */
597     public function display(core_backup_renderer $renderer) {
599         // Get the resulting stored_file record.
600         $type = $this->get_ui()->get_controller()->get_type();
601         $courseid = $this->get_ui()->get_controller()->get_courseid();
602         switch ($type) {
603             case 'activity':
604                 $cmid = $this->get_ui()->get_controller()->get_id();
605                 $cm = get_coursemodule_from_id(null, $cmid, $courseid);
606                 $modcontext = context_module::instance($cm->id);
607                 $restorerul = new moodle_url('/backup/restorefile.php', array('contextid' => $modcontext->id));
608                 break;
609             case 'course':
610             default:
611                 $coursecontext = context_course::instance($courseid);
612                 $restorerul = new moodle_url('/backup/restorefile.php', array('contextid' => $coursecontext->id));
613         }
615         $output = '';
616         $output .= $renderer->box_start();
617         if (!empty($this->results['include_file_references_to_external_content'])) {
618             $output .= $renderer->notification(get_string('filereferencesincluded', 'backup'), 'notifyproblem');
619         }
620         if (!empty($this->results['missing_files_in_pool'])) {
621             $output .= $renderer->notification(get_string('missingfilesinpool', 'backup'), 'notifyproblem');
622         }
623         $output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
624         $output .= $renderer->continue_button($restorerul);
625         $output .= $renderer->box_end();
627         return $output;
628     }