dd58ca876cec9fbaac459352bcd5a9b8590d827b
[moodle.git] / backup / util / ui / restore_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  * restore user interface stages
20  *
21  * This file contains the classes required to manage the stages that make up the
22  * restore user interface.
23  * These will be primarily operated a {@see restore_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 restore stages (a requirement of many restore ui functions).
34  * Each stage must then define two abstract methods
35  *  - process : To process the stage
36  *  - initialise_stage_form : To get a restore_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 restore_ui_stage extends base_ui_stage {
42     /**
43      * Constructor
44      * @param restore_ui $ui
45      */
46     public function __construct(restore_ui $ui, array $params=null) {
47         $this->ui = $ui;
48         $this->params = $params;
49     }
50     /**
51      * The restore id from the restore controller
52      * @return string
53      */
54     final public function get_restoreid() {
55         return $this->get_uniqueid();
56     }
57     /**
58      * This is an independent stage
59      * @return int
60      */
61     final public function is_independent() {
62         return false;
63     }
65     /**
66      * No sub stages for this stage
67      * @return false
68      */
69     public function has_sub_stages() {
70         return false;
71     }
73     /**
74      * The name of this stage
75      * @return string
76      */
77     final public function get_name() {
78         return get_string('restorestage'.$this->stage,'backup');
79     }
80     /**
81      * Returns true if this is the settings stage
82      * @return bool
83      */
84     final public function is_first_stage() {
85         return $this->stage == restore_ui::STAGE_SETTINGS;
86     }
87 }
89 /**
90  * Abstract class used to represent a restore stage that is indenependent.
91  *
92  * An independent stage is a judged to be so because it doesn't require, and has
93  * no use for the restore controller.
94  */
95 abstract class restore_ui_independent_stage {
96     /**
97      * @var core_backup_progress Optional progress reporter
98      */
99     private $progressreporter;
101     abstract public function __construct($contextid);
102     abstract public function process();
103     abstract public function display(core_backup_renderer $renderer);
104     abstract public function get_stage();
106     /**
107      * Gets the progress reporter object in use for this restore UI stage.
108      *
109      * IMPORTANT: This progress reporter is used only for UI progress that is
110      * outside the restore controller. The restore controller has its own
111      * progress reporter which is used for progress during the main restore.
112      * Use the restore controller's progress reporter to report progress during
113      * a restore operation, not this one.
114      *
115      * This extra reporter is necessary because on some restore UI screens,
116      * there are long-running tasks even though there is no restore controller
117      * in use. There is a similar function in restore_ui. but that class is not
118      * used on some stages.
119      *
120      * @return core_backup_null_progress
121      */
122     public function get_progress_reporter() {
123         if (!$this->progressreporter) {
124             $this->progressreporter = new core_backup_null_progress();
125         }
126         return $this->progressreporter;
127     }
129     /**
130      * Sets the progress reporter that will be returned by get_progress_reporter.
131      *
132      * @param core_backup_progress $progressreporter Progress reporter
133      */
134     public function set_progress_reporter(core_backup_progress $progressreporter) {
135         $this->progressreporter = $progressreporter;
136     }
138     /**
139      * Gets an array of progress bar items that can be displayed through the restore renderer.
140      * @return array Array of items for the progress bar
141      */
142     public function get_progress_bar() {
143         global $PAGE;
144         $stage = restore_ui::STAGE_COMPLETE;
145         $currentstage = $this->get_stage();
146         $items = array();
147         while ($stage > 0) {
148             $classes = array('backup_stage');
149             if (floor($stage/2) == $currentstage) {
150                 $classes[] = 'backup_stage_next';
151             } else if ($stage == $currentstage) {
152                 $classes[] = 'backup_stage_current';
153             } else if ($stage < $currentstage) {
154                 $classes[] = 'backup_stage_complete';
155             }
156             $item = array('text' => strlen(decbin($stage)).'. '.get_string('restorestage'.$stage, 'backup'),'class' => join(' ', $classes));
157             if ($stage < $currentstage && $currentstage < restore_ui::STAGE_COMPLETE) {
158                 //$item['link'] = new moodle_url($PAGE->url, array('restore'=>$this->get_restoreid(), 'stage'=>$stage));
159             }
160             array_unshift($items, $item);
161             $stage = floor($stage/2);
162         }
163         return $items;
164     }
165     abstract public function get_stage_name();
166     /**
167      * Obviously true
168      * @return true
169      */
170     final public function is_independent() {
171         return true;
172     }
173     public function destroy() {
174         // Nothing to destroy here!
175     }
178 /**
179  * The confirmation stage.
180  *
181  * This is the first stage, it is independent.
182  */
183 class restore_ui_stage_confirm extends restore_ui_independent_stage implements file_progress {
185     protected $contextid;
186     protected $filename = null;
187     protected $filepath = null;
188     protected $details;
190     /**
191      * @var bool True if we have started reporting progress
192      */
193     protected $startedprogress = false;
195     public function __construct($contextid) {
196         $this->contextid = $contextid;
197         $this->filename = required_param('filename', PARAM_FILE);
198     }
199     public function process() {
200         global $CFG;
201         if (!file_exists("$CFG->tempdir/backup/".$this->filename)) {
202             throw new restore_ui_exception('invalidrestorefile');
203         }
204         $outcome = $this->extract_file_to_dir();
205         if ($outcome) {
206             fulldelete($this->filename);
207         }
208         return $outcome;
209     }
210     protected function extract_file_to_dir() {
211         global $CFG, $USER;
213         $this->filepath = restore_controller::get_tempdir_name($this->contextid, $USER->id);
215         $fb = get_file_packer('application/vnd.moodle.backup');
216         $result = $fb->extract_to_pathname("$CFG->tempdir/backup/".$this->filename,
217                 "$CFG->tempdir/backup/$this->filepath/", null, $this);
219         // If any progress happened, end it.
220         if ($this->startedprogress) {
221             $this->get_progress_reporter()->end_progress();
222         }
223         return $result;
224     }
226     /**
227      * Implementation for file_progress interface to display unzip progress.
228      *
229      * @param int $progress Current progress
230      * @param int $max Max value
231      */
232     public function progress($progress = file_progress::INDETERMINATE, $max = file_progress::INDETERMINATE) {
233         $reporter = $this->get_progress_reporter();
235         // Start tracking progress if necessary.
236         if (!$this->startedprogress) {
237             $reporter->start_progress('extract_file_to_dir',
238                     ($max == file_progress::INDETERMINATE) ? core_backup_progress::INDETERMINATE : $max);
239             $this->startedprogress = true;
240         }
242         // Pass progress through to whatever handles it.
243         $reporter->progress(
244                 ($progress == file_progress::INDETERMINATE) ? core_backup_progress::INDETERMINATE : $progress);
245     }
247     /**
248      * Renders the confirmation stage screen
249      *
250      * @param core_backup_renderer $renderer renderer instance to use
251      * @return string HTML code
252      */
253     public function display(core_backup_renderer $renderer) {
255         $prevstageurl = new moodle_url('/backup/restorefile.php', array('contextid' => $this->contextid));
256         $nextstageurl = new moodle_url('/backup/restore.php', array(
257             'contextid' => $this->contextid,
258             'filepath'  => $this->filepath,
259             'stage'     => restore_ui::STAGE_DESTINATION));
261         $format = backup_general_helper::detect_backup_format($this->filepath);
263         if ($format === backup::FORMAT_UNKNOWN) {
264             // unknown format - we can't do anything here
265             return $renderer->backup_details_unknown($prevstageurl);
267         } else if ($format !== backup::FORMAT_MOODLE) {
268             // non-standard format to be converted
269             $details = array('format' => $format, 'type' => backup::TYPE_1COURSE); // todo type to be returned by a converter
270             return $renderer->backup_details_nonstandard($nextstageurl, $details);
272         } else {
273             // standard MBZ backup, let us get information from it and display
274             $this->details = backup_general_helper::get_backup_information($this->filepath);
275             return $renderer->backup_details($this->details, $nextstageurl);
276         }
277     }
279     public function get_stage_name() {
280         return get_string('restorestage'.restore_ui::STAGE_CONFIRM, 'backup');
281     }
282     public function get_stage() {
283         return restore_ui::STAGE_CONFIRM;
284     }
287 /**
288  * This is the destination stage.
289  *
290  * This stage is the second stage and is also independent
291  */
292 class restore_ui_stage_destination extends restore_ui_independent_stage {
293     protected $contextid;
294     protected $filepath = null;
295     protected $courseid = null;
296     protected $target = backup::TARGET_NEW_COURSE;
297     protected $coursesearch = null;
298     protected $categorysearch = null;
299     public function __construct($contextid) {
300         global $PAGE;
301         $this->contextid = $contextid;
302         $this->filepath = required_param('filepath', PARAM_ALPHANUM);
303         $url = new moodle_url($PAGE->url, array(
304             'filepath'=>$this->filepath,
305             'contextid'=>$this->contextid,
306             'stage'=>restore_ui::STAGE_DESTINATION));
307         $this->coursesearch = new restore_course_search(array('url'=>$url), context::instance_by_id($contextid)->instanceid);
308         $this->categorysearch = new restore_category_search(array('url'=>$url));
309     }
310     public function process() {
311         global $CFG, $DB;
312         if (!file_exists("$CFG->tempdir/backup/".$this->filepath) || !is_dir("$CFG->tempdir/backup/".$this->filepath)) {
313             throw new restore_ui_exception('invalidrestorepath');
314         }
315         if (optional_param('searchcourses', false, PARAM_BOOL)) {
316             return false;
317         }
318         $this->target = optional_param('target', backup::TARGET_NEW_COURSE, PARAM_INT);
319         $targetid = optional_param('targetid', null, PARAM_INT);
320         if (!is_null($this->target) && !is_null($targetid) && confirm_sesskey()) {
321             if ($this->target == backup::TARGET_NEW_COURSE) {
322                 list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'), get_string('restoringcourseshortname', 'backup'));
323                 $this->courseid = restore_dbops::create_new_course($fullname, $shortname, $targetid);
324             } else {
325                 $this->courseid = $targetid;
326             }
327             return ($DB->record_exists('course', array('id'=>$this->courseid)));
328         }
329         return false;
330     }
332     /**
333      * Renders the destination stage screen
334      *
335      * @param core_backup_renderer $renderer renderer instance to use
336      * @return string HTML code
337      */
338     public function display(core_backup_renderer $renderer) {
340         $format = backup_general_helper::detect_backup_format($this->filepath);
342         if ($format === backup::FORMAT_MOODLE) {
343             // standard Moodle 2 format, let use get the type of the backup
344             $details = backup_general_helper::get_backup_information($this->filepath);
345             if ($details->type === backup::TYPE_1COURSE) {
346                 $wholecourse = true;
347             } else {
348                 $wholecourse = false;
349             }
351         } else {
352             // non-standard format to be converted. We assume it contains the
353             // whole course for now. However, in the future there might be a callback
354             // to the installed converters
355             $wholecourse = true;
356         }
358         $nextstageurl = new moodle_url('/backup/restore.php', array(
359             'contextid' => $this->contextid,
360             'filepath'  => $this->filepath,
361             'stage'     => restore_ui::STAGE_SETTINGS));
362         $context = context::instance_by_id($this->contextid);
364         if ($context->contextlevel == CONTEXT_COURSE and has_capability('moodle/restore:restorecourse', $context)) {
365             $currentcourse = $context->instanceid;
366         } else {
367             $currentcourse = false;
368         }
370         return $renderer->course_selector($nextstageurl, $wholecourse, $this->categorysearch, $this->coursesearch, $currentcourse);
371     }
373     public function get_stage_name() {
374         return get_string('restorestage'.restore_ui::STAGE_DESTINATION, 'backup');
375     }
376     public function get_filepath() {
377         return $this->filepath;
378     }
379     public function get_course_id() {
380         return $this->courseid;
381     }
382     public function get_stage() {
383         return restore_ui::STAGE_DESTINATION;
384     }
385     public function get_target() {
386         return $this->target;
387     }
389 /**
390  * This stage is the settings stage.
391  *
392  * This stage is the third stage, it is dependent on a restore controller and
393  * is the first stage as such.
394  */
395 class restore_ui_stage_settings extends restore_ui_stage {
396     /**
397      * Initial restore stage constructor
398      * @param restore_ui $ui
399      */
400     public function __construct(restore_ui $ui, array $params=null) {
401         $this->stage = restore_ui::STAGE_SETTINGS;
402         parent::__construct($ui, $params);
403     }
405     public function process(base_moodleform $form=null) {
406         $form = $this->initialise_stage_form();
408         if ($form->is_cancelled()) {
409             $this->ui->cancel_process();
410         }
412         $data = $form->get_data();
413         if ($data && confirm_sesskey()) {
414             $tasks = $this->ui->get_tasks();
415             $changes = 0;
416             foreach ($tasks as &$task) {
417                 // We are only interesting in the backup root task for this stage
418                 if ($task instanceof restore_root_task || $task instanceof restore_course_task) {
419                     // Get all settings into a var so we can iterate by reference
420                     $settings = $task->get_settings();
421                     foreach ($settings as &$setting) {
422                         $name = $setting->get_ui_name();
423                         if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
424                             $setting->set_value($data->$name);
425                             $changes++;
426                         } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
427                             $setting->set_value(0);
428                             $changes++;
429                         }
430                     }
431                 }
432             }
433             // Return the number of changes the user made
434             return $changes;
435         } else {
436             return false;
437         }
438     }
440     protected function initialise_stage_form() {
441         global $PAGE;
442         if ($this->stageform === null) {
443             $form = new restore_settings_form($this, $PAGE->url);
444             // Store as a variable so we can iterate by reference
445             $tasks = $this->ui->get_tasks();
446             $headingprinted = false;
447             // Iterate all tasks by reference
448             foreach ($tasks as &$task) {
449                 // For the initial stage we are only interested in the root settings
450                 if ($task instanceof restore_root_task) {
451                     if (!$headingprinted) {
452                         $form->add_heading('rootsettings', get_string('restorerootsettings', 'backup'));
453                         $headingprinted = true;
454                     }
455                     $settings = $task->get_settings();
456                     // First add all settings except the filename setting
457                     foreach ($settings as &$setting) {
458                         if ($setting->get_name() == 'filename') {
459                             continue;
460                         }
461                         $form->add_setting($setting, $task);
462                     }
463                     // Then add all dependencies
464                     foreach ($settings as &$setting) {
465                         if ($setting->get_name() == 'filename') {
466                             continue;
467                         }
468                         $form->add_dependencies($setting);
469                     }
470                 }
471             }
472             $this->stageform = $form;
473         }
474         // Return the form
475         return $this->stageform;
476     }
479 /**
480  * Schema stage of backup process
481  *
482  * During the schema stage the user is required to set the settings that relate
483  * to the area that they are backing up as well as its children.
484  *
485  * @copyright 2010 Sam Hemelryk
486  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
487  */
488 class restore_ui_stage_schema extends restore_ui_stage {
489     /**
490      * Schema stage constructor
491      * @param backup_moodleform $ui
492      */
493     public function __construct(restore_ui $ui, array $params=null) {
494         $this->stage = restore_ui::STAGE_SCHEMA;
495         parent::__construct($ui, $params);
496     }
497     /**
498      * Processes the schema stage
499      *
500      * @param backup_moodleform|null $form
501      * @return int The number of changes the user made
502      */
503     public function process(base_moodleform $form = null) {
504         $form = $this->initialise_stage_form();
505         // Check it wasn't cancelled
506         if ($form->is_cancelled()) {
507             $this->ui->cancel_process();
508         }
510         // Check it has been submit
511         $data = $form->get_data();
512         if ($data && confirm_sesskey()) {
513             // Get the tasks into a var so we can iterate by reference
514             $tasks = $this->ui->get_tasks();
515             $changes = 0;
516             // Iterate all tasks by reference
517             foreach ($tasks as &$task) {
518                 // We are only interested in schema settings
519                 if (!($task instanceof restore_root_task)) {
520                     // Store as a variable so we can iterate by reference
521                     $settings = $task->get_settings();
522                     // Iterate by reference
523                     foreach ($settings as &$setting) {
524                         $name = $setting->get_ui_name();
525                         if (isset($data->$name) &&  $data->$name != $setting->get_value()) {
526                             $setting->set_value($data->$name);
527                             $changes++;
528                         } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
529                             $setting->set_value(0);
530                             $changes++;
531                         }
532                     }
533                 }
534             }
535             // Return the number of changes the user made
536             return $changes;
537         } else {
538             return false;
539         }
540     }
541     /**
542      * Creates the backup_schema_form instance for this stage
543      *
544      * @return backup_schema_form
545      */
546     protected function initialise_stage_form() {
547         global $PAGE;
548         if ($this->stageform === null) {
549             $form = new restore_schema_form($this, $PAGE->url);
550             $tasks = $this->ui->get_tasks();
551             $courseheading = false;
553             $allsettings = array();
554             foreach ($tasks as $task) {
555                 if (!($task instanceof restore_root_task)) {
556                     if (!$courseheading) {
557                         // If we havn't already display a course heading to group nicely
558                         $form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
559                         $courseheading = true;
560                     }
561                     // Put each setting into an array of settings to add. Adding
562                     // a setting individually is a very slow operation, so we add
563                     // them all in a batch later on.
564                     foreach ($task->get_settings() as $setting) {
565                         $allsettings[] = array($setting, $task);
566                     }
567                 } else if ($this->ui->enforce_changed_dependencies()) {
568                     // Only show these settings if dependencies changed them.
569                     // Add a root settings heading to group nicely
570                     $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
571                     // Iterate all settings and add them to the form as a fixed
572                     // setting. We only want schema settings to be editable
573                     foreach ($task->get_settings() as $setting) {
574                         if ($setting->get_name() != 'filename') {
575                             $form->add_fixed_setting($setting, $task);
576                         }
577                     }
578                 }
579             }
581             // Actually add all the settings that we put in the array.
582             $form->add_settings($allsettings);
584             // Add the dependencies for all the settings.
585             foreach ($allsettings as $settingtask) {
586                 $form->add_dependencies($settingtask[0]);
587             }
589             $this->stageform = $form;
590         }
591         return $this->stageform;
592     }
595 /**
596  * Confirmation stage
597  *
598  * On this stage the user reviews the setting for the backup and can change the filename
599  * of the file that will be generated.
600  *
601  * @copyright 2010 Sam Hemelryk
602  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
603  */
604 class restore_ui_stage_review extends restore_ui_stage {
605     /**
606      * Constructs the stage
607      * @param restore_ui $ui
608      */
609     public function __construct($ui, array $params=null) {
610         $this->stage = restore_ui::STAGE_REVIEW;
611         parent::__construct($ui, $params);
612     }
613     /**
614      * Processes the confirmation stage
615      *
616      * @param backup_moodleform $form
617      * @return int The number of changes the user made
618      */
619     public function process(base_moodleform $form = null) {
620         $form = $this->initialise_stage_form();
621         // Check it hasn't been cancelled
622         if ($form->is_cancelled()) {
623             $this->ui->cancel_process();
624         }
626         $data = $form->get_data();
627         if ($data && confirm_sesskey()) {
628             return 0;
629         } else {
630             return false;
631         }
632     }
633     /**
634      * Creates the backup_confirmation_form instance this stage requires
635      *
636      * @return backup_confirmation_form
637      */
638     protected function initialise_stage_form() {
639         global $PAGE;
640         if ($this->stageform === null) {
641             // Get the form
642             $form = new restore_review_form($this, $PAGE->url);
643             $content = '';
644             $courseheading = false;
646             $progress = $this->ui->get_progress_reporter();
647             $tasks = $this->ui->get_tasks();
648             $progress->start_progress('initialise_stage_form', count($tasks));
649             $done = 1;
650             foreach ($tasks as $task) {
651                 if ($task instanceof restore_root_task) {
652                     // If its a backup root add a root settings heading to group nicely
653                     $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
654                 } else if (!$courseheading) {
655                     // we havn't already add a course heading
656                     $form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
657                     $courseheading = true;
658                 }
659                 // Iterate all settings, doesnt need to happen by reference
660                 foreach ($task->get_settings() as $setting) {
661                     $form->add_fixed_setting($setting, $task);
662                 }
663                 // Update progress.
664                 $progress->progress($done++);
665             }
666             $progress->end_progress();
667             $this->stageform = $form;
668         }
669         return $this->stageform;
670     }
673 /**
674  * Final stage of backup
675  *
676  * This stage is special in that it is does not make use of a form. The reason for
677  * this is the order of procession of backup at this stage.
678  * The processesion is:
679  * 1. The final stage will be intialise.
680  * 2. The confirmation stage will be processed.
681  * 3. The backup will be executed
682  * 4. The complete stage will be loaded by execution
683  * 5. The complete stage will be displayed
684  *
685  * This highlights that we neither need a form nor a display method for this stage
686  * we simply need to process.
687  *
688  * @copyright 2010 Sam Hemelryk
689  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
690  */
691 class restore_ui_stage_process extends restore_ui_stage {
693     const SUBSTAGE_NONE = 0;
694     const SUBSTAGE_PRECHECKS = 2;
696     protected $substage = 0;
698     /**
699      * Constructs the final stage
700      * @param backup_ui $ui
701      */
702     public function __construct(base_ui $ui, array $params=null) {
703         $this->stage = restore_ui::STAGE_PROCESS;
704         parent::__construct($ui, $params);
705     }
706     /**
707      * Processes the final stage.
708      *
709      * In this case it checks to see if there is a sub stage that we need to display
710      * before execution, if there is we gear up to display the subpage, otherwise
711      * we return true which will lead to execution of the restore and the loading
712      * of the completed stage.
713      */
714     public function process(base_moodleform $form=null) {
715         if (optional_param('cancel', false, PARAM_BOOL)) {
716             redirect(new moodle_url('/course/view.php', array('id'=>$this->get_ui()->get_controller()->get_courseid())));
717         }
719         // First decide whether a substage is needed
720         $rc = $this->ui->get_controller();
721         if ($rc->get_status() == backup::STATUS_SETTING_UI) {
722             $rc->finish_ui();
723         }
724         if ($rc->get_status() == backup::STATUS_NEED_PRECHECK) {
725             if (!$rc->precheck_executed()) {
726                 $rc->execute_precheck(true);
727             }
728             $results = $rc->get_precheck_results();
729             if (!empty($results)) {
730                 $this->substage = self::SUBSTAGE_PRECHECKS;
731             }
732         }
734         $substage = optional_param('substage', null, PARAM_INT);
735         if (empty($this->substage) && !empty($substage)) {
736             $this->substage = $substage;
737             // Now check whether that substage has already been submit
738             if ($this->substage == self::SUBSTAGE_PRECHECKS && optional_param('sesskey', null, PARAM_RAW) == sesskey()) {
739                 $info = $rc->get_info();
740                 if (!empty($info->role_mappings->mappings)) {
741                     foreach ($info->role_mappings->mappings as $key=>&$mapping) {
742                         $mapping->targetroleid = optional_param('mapping'.$key, $mapping->targetroleid, PARAM_INT);
743                     }
744                     $info->role_mappings->modified = true;
745                 }
746                 // We've processed the substage now setting it back to none so we
747                 // can move to the next stage.
748                 $this->substage = self::SUBSTAGE_NONE;
749             }
750         }
752         return empty($this->substage);
753     }
754     /**
755      * should NEVER be called... throws an exception
756      */
757     protected function initialise_stage_form() {
758         throw new backup_ui_exception('backup_ui_must_execute_first');
759     }
761     /**
762      * Renders the process stage screen
763      *
764      * @param core_backup_renderer $renderer renderer instance to use
765      * @return string HTML code
766      */
767     public function display(core_backup_renderer $renderer) {
768         global $PAGE;
770         $html = '';
771         $haserrors = false;
772         $url = new moodle_url($PAGE->url, array(
773             'restore'   => $this->get_uniqueid(),
774             'stage'     => restore_ui::STAGE_PROCESS,
775             'substage'  => $this->substage,
776             'sesskey'   => sesskey()));
777         $html .= html_writer::start_tag('form', array(
778             'action'    => $url->out_omit_querystring(),
779             'class'     => 'backup-restore',
780             'method'    => 'post'));
781         foreach ($url->params() as $name => $value) {
782             $html .= html_writer::empty_tag('input', array(
783                 'type'  => 'hidden',
784                 'name'  => $name,
785                 'value' => $value));
786         }
787         switch ($this->substage) {
788             case self::SUBSTAGE_PRECHECKS :
789                 $results = $this->ui->get_controller()->get_precheck_results();
790                 $info = $this->ui->get_controller()->get_info();
791                 $haserrors = (!empty($results['errors']));
792                 $html .= $renderer->precheck_notices($results);
793                 if (!empty($info->role_mappings->mappings)) {
794                     $context = context_course::instance($this->ui->get_controller()->get_courseid());
795                     $assignableroles = get_assignable_roles($context, ROLENAME_ALIAS, false);
796                     $html .= $renderer->role_mappings($info->role_mappings->mappings, $assignableroles);
797                 }
798                 break;
799             default:
800                 throw new restore_ui_exception('backup_ui_must_execute_first');
801         }
802         $html .= $renderer->substage_buttons($haserrors);
803         $html .= html_writer::end_tag('form');
805         return $html;
806     }
808     public function has_sub_stages() {
809         return true;
810     }
813 /**
814  * This is the completed stage.
815  *
816  * Once this is displayed there is nothing more to do.
817  */
818 class restore_ui_stage_complete extends restore_ui_stage_process {
819     /**
820      * The results of the backup execution
821      * @var array
822      */
823     protected $results;
824     /**
825      * Constructs the complete backup stage
826      * @param backup_ui $ui
827      * @param array|null $params
828      * @param array $results
829      */
830     public function __construct(restore_ui $ui, array $params=null, array $results=null) {
831         $this->results = $results;
832         parent::__construct($ui, $params);
833         $this->stage = restore_ui::STAGE_COMPLETE;
834     }
836     /**
837      * Displays the completed backup stage.
838      *
839      * Currently this just envolves redirecting to the file browser with an
840      * appropriate message.
841      *
842      * @param core_backup_renderer $renderer
843      * @return string HTML code to echo
844      */
845     public function display(core_backup_renderer $renderer) {
847         $html  = '';
848         if (!empty($this->results['file_aliases_restore_failures'])) {
849             $html .= $renderer->box_start('generalbox filealiasesfailures');
850             $html .= $renderer->heading_with_help(get_string('filealiasesrestorefailures', 'core_backup'),
851                 'filealiasesrestorefailures', 'core_backup');
852             $html .= $renderer->container(get_string('filealiasesrestorefailuresinfo', 'core_backup'));
853             $html .= $renderer->container_start('aliaseslist');
854             $html .= html_writer::start_tag('ul');
855             foreach ($this->results['file_aliases_restore_failures'] as $alias) {
856                 $html .= html_writer::tag('li', s($alias));
857             }
858             $html .= html_writer::end_tag('ul');
859             $html .= $renderer->container_end();
860             $html .= $renderer->box_end();
861         }
862         $html .= $renderer->box_start();
863         if (array_key_exists('file_missing_in_backup', $this->results)) {
864             $html .= $renderer->notification(get_string('restorefileweremissing', 'backup'), 'notifyproblem');
865         }
866         $html .= $renderer->notification(get_string('restoreexecutionsuccess', 'backup'), 'notifysuccess');
867         $html .= $renderer->continue_button(new moodle_url('/course/view.php', array(
868             'id' => $this->get_ui()->get_controller()->get_courseid())), 'get');
869         $html .= $renderer->box_end();
871         return $html;
872     }