community block MDL-23481 integrate restore operation
[moodle.git] / backup / util / ui / restore_ui_stage.class.php
CommitLineData
785d6603
SH
1<?php
2
3
4// This file is part of Moodle - http://moodle.org/
5//
6// Moodle is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// Moodle is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18
19/**
20 * restore user interface stages
21 *
22 * This file contains the classes required to manage the stages that make up the
23 * restore user interface.
24 * These will be primarily operated a {@see restore_ui} instance.
25 *
26 * @package moodlecore
27 * @copyright 2010 Sam Hemelryk
28 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 */
30
31/**
32 * Abstract stage class
33 *
34 * This class should be extended by all restore stages (a requirement of many restore ui functions).
35 * Each stage must then define two abstract methods
36 * - process : To process the stage
37 * - initialise_stage_form : To get a restore_moodleform instance for the stage
38 *
39 * @copyright 2010 Sam Hemelryk
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 */
42abstract class restore_ui_stage extends base_ui_stage {
43 /**
44 *
45 * @param restore_ui $ui
46 */
47 public function __construct(restore_ui $ui, array $params=null) {
48 $this->ui = $ui;
49 $this->params = $params;
50 }
51 /**
52 * The restore id from the restore controller
53 * @return string
54 */
55 final public function get_restoreid() {
56 return $this->get_uniqueid();
57 }
58
59 final public function is_independent() {
60 return false;
61 }
62
63 public function has_sub_stages() {
64 return false;
65 }
66
67 /**
68 * The name of this stage
69 * @return string
70 */
71 final public function get_name() {
72 return get_string('restorestage'.$this->stage,'backup');
73 }
74}
75
76abstract class restore_ui_independent_stage {
77 abstract public function __construct($contextid);
78 abstract public function process();
79 abstract public function display($renderer);
80 abstract public function get_stage();
81 /**
82 * Gets an array of progress bar items that can be displayed through the restore renderer.
83 * @return array Array of items for the progress bar
84 */
85 public function get_progress_bar() {
86 global $PAGE;
87 $stage = restore_ui::STAGE_COMPLETE;
88 $currentstage = $this->get_stage();
89 $items = array();
90 while ($stage > 0) {
91 $classes = array('backup_stage');
92 if (floor($stage/2) == $currentstage) {
93 $classes[] = 'backup_stage_next';
94 } else if ($stage == $currentstage) {
95 $classes[] = 'backup_stage_current';
96 } else if ($stage < $currentstage) {
97 $classes[] = 'backup_stage_complete';
98 }
99 $item = array('text' => strlen(decbin($stage)).'. '.get_string('restorestage'.$stage, 'backup'),'class' => join(' ', $classes));
100 if ($stage < $currentstage && $currentstage < restore_ui::STAGE_COMPLETE) {
101 //$item['link'] = new moodle_url($PAGE->url, array('restore'=>$this->get_restoreid(), 'stage'=>$stage));
102 }
103 array_unshift($items, $item);
104 $stage = floor($stage/2);
105 }
106 return $items;
107 }
108 abstract public function get_stage_name();
109 final public function is_independent() {
110 return true;
111 }
112}
113
114class restore_ui_stage_confirm extends restore_ui_independent_stage {
115 protected $contextid;
116 protected $filename = null;
117 protected $filepath = null;
118 protected $details;
119 public function __construct($contextid) {
120 $this->contextid = $contextid;
121 $this->filename = required_param('filename', PARAM_FILE);
122 }
123 public function process() {
124 global $CFG;
125 if (!file_exists("$CFG->dataroot/temp/backup/".$this->filename)) {
126 throw new restore_ui_exception('invalidrestorefile');
127 }
128 return $this->extract_file_to_dir();
129 }
130 protected function extract_file_to_dir() {
131 global $CFG, $USER;
132
133 $this->filepath = restore_controller::get_tempdir_name($this->contextid, $USER->id);
134
135 $fb = get_file_packer();
136 return ($fb->extract_to_pathname("$CFG->dataroot/temp/backup/".$this->filename, "$CFG->dataroot/temp/backup/$this->filepath/"));
137 }
138 public function display($renderer) {
139 $this->details = backup_general_helper::get_backup_information($this->filepath);
140 return $renderer->backup_details($this->details, new moodle_url('/backup/restore.php', array('contextid'=>$this->contextid, 'filepath'=>$this->filepath, 'stage'=>restore_ui::STAGE_DESTINATION)));
141 }
142 public function get_stage_name() {
143 return get_string('restorestage'.restore_ui::STAGE_CONFIRM, 'backup');
144 }
145 public function get_stage() {
146 return restore_ui::STAGE_CONFIRM;
147 }
148}
149
150class restore_ui_stage_destination extends restore_ui_independent_stage {
151 protected $contextid;
152 protected $filepath = null;
153 protected $details;
154 protected $courseid = null;
155 public function __construct($contextid) {
156 $this->contextid = $contextid;
157 $this->filepath = required_param('filepath', PARAM_ALPHANUM);
158 }
159 public function process() {
160 global $CFG, $DB;
161 if (!file_exists("$CFG->dataroot/temp/backup/".$this->filepath) || !is_dir("$CFG->dataroot/temp/backup/".$this->filepath)) {
162 throw new restore_ui_exception('invalidrestorepath');
163 }
164 $target = optional_param('target', null, PARAM_INT);
165 if (!is_null($target) && confirm_sesskey()) {
166 $targetid = required_param('targetid', PARAM_INT);
167 if ($target == backup::TARGET_NEW_COURSE) {
168 list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'), get_string('restoringcourseshortname', 'backup'));
169 $this->courseid = restore_dbops::create_new_course($fullname, $shortname, $targetid);
170 } else {
171 $this->courseid = $targetid;
172 }
173 return ($DB->record_exists('course', array('id'=>$this->courseid)));
174 }
175 return false;
176 }
177 /**
178 *
179 * @global moodle_database $DB
180 * @param core_backup_renderer $renderer
181 * @return string
182 */
183 public function display($renderer) {
184 global $DB;
185 $this->details = backup_general_helper::get_backup_information($this->filepath);
186 $url = new moodle_url('/backup/restore.php', array('contextid'=>$this->contextid, 'filepath'=>$this->filepath, 'stage'=>restore_ui::STAGE_SETTINGS));
187 $context = get_context_instance_by_id($this->contextid);
188 $currentcourse = ($context->contextlevel == CONTEXT_COURSE)?$context->instanceid:false;
189 $courselist = array();
190 $courses = $DB->get_recordset('course', array(), 'id,fullname,shortname');
191 foreach ($courses as $course) {
192 $courselist[$course->id] = $course->fullname.' ['.$course->shortname.']';
193 }
194 $courses->close();
195 $html = $renderer->course_selector($url, $this->details, make_categories_options(), $courselist, $currentcourse);
196 return $html;
197 }
198 public function get_stage_name() {
199 return get_string('restorestage'.restore_ui::STAGE_DESTINATION, 'backup');
200 }
201 public function get_filepath() {
202 return $this->filepath;
203 }
204 public function get_course_id() {
205 return $this->courseid;
206 }
207 public function get_stage() {
208 return restore_ui::STAGE_DESTINATION;
209 }
210}
211
212class restore_ui_stage_settings extends restore_ui_stage {
213 /**
214 * Initial restore stage constructor
215 * @param restore_ui $ui
216 */
217 public function __construct(restore_ui $ui, array $params=null) {
218 $this->stage = restore_ui::STAGE_SETTINGS;
219 parent::__construct($ui, $params);
220 }
221
222 public function process(base_moodleform $form=null) {
223 $form = $this->initialise_stage_form();
224
225 if ($form->is_cancelled()) {
226 $this->ui->cancel_restore();
227 }
228
229 $data = $form->get_data();
230 if ($data && confirm_sesskey()) {
231 $tasks = $this->ui->get_tasks();
232 $changes = 0;
233 foreach ($tasks as &$task) {
234 // We are only interesting in the backup root task for this stage
235 if ($task instanceof restore_root_task || $task instanceof restore_course_task) {
236 // Get all settings into a var so we can iterate by reference
237 $settings = $task->get_settings();
238 foreach ($settings as &$setting) {
239 $name = $setting->get_ui_name();
240 if (isset($data->$name) && $data->$name != $setting->get_value()) {
241 $setting->set_value($data->$name);
242 $changes++;
243 } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
244 $setting->set_value(0);
245 $changes++;
246 }
247 }
248 }
249 }
250 // Return the number of changes the user made
251 return $changes;
252 } else {
253 return false;
254 }
255 }
256
257 protected function initialise_stage_form() {
258 global $PAGE;
259 if ($this->stageform === null) {
260 $form = new restore_settings_form($this, $PAGE->url);
261 // Store as a variable so we can iterate by reference
262 $tasks = $this->ui->get_tasks();
263 $headingprinted = false;
264 // Iterate all tasks by reference
265 foreach ($tasks as &$task) {
266 // For the initial stage we are only interested in the root settings
267 if ($task instanceof restore_root_task) {
268 if (!$headingprinted) {
269 $form->add_heading('rootsettings', get_string('restorerootsettings', 'backup'));
270 $headingprinted = true;
271 }
272 $settings = $task->get_settings();
273 // First add all settings except the filename setting
274 foreach ($settings as &$setting) {
275 if ($setting->get_name() == 'filename') {
276 continue;
277 }
278 $form->add_setting($setting, $task);
279 }
280 // Then add all dependencies
281 foreach ($settings as &$setting) {
282 if ($setting->get_name() == 'filename') {
283 continue;
284 }
285 $form->add_dependencies($setting);
286 }
287 }
288 }
289 $this->stageform = $form;
290 }
291 // Return the form
292 return $this->stageform;
293 }
294}
295
296/**
297 * Schema stage of backup process
298 *
299 * During the schema stage the user is required to set the settings that relate
300 * to the area that they are backing up as well as its children.
301 *
302 * @copyright 2010 Sam Hemelryk
303 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
304 */
305class restore_ui_stage_schema extends restore_ui_stage {
306 /**
307 * Schema stage constructor
308 * @param backup_moodleform $ui
309 */
310 public function __construct(restore_ui $ui, array $params=null) {
311 $this->stage = restore_ui::STAGE_SCHEMA;
312 parent::__construct($ui, $params);
313 }
314 /**
315 * Processes the schema stage
316 *
317 * @param backup_moodleform|null $form
318 * @return int The number of changes the user made
319 */
320 public function process(base_moodleform $form = null) {
321 $form = $this->initialise_stage_form();
322 // Check it wasn't cancelled
323 if ($form->is_cancelled()) {
324 $this->ui->cancel_backup();
325 }
326
327 // Check it has been submit
328 $data = $form->get_data();
329 if ($data && confirm_sesskey()) {
330 // Get the tasks into a var so we can iterate by reference
331 $tasks = $this->ui->get_tasks();
332 $changes = 0;
333 // Iterate all tasks by reference
334 foreach ($tasks as &$task) {
335 // We are only interested in schema settings
336 if (!($task instanceof restore_root_task)) {
337 // Store as a variable so we can iterate by reference
338 $settings = $task->get_settings();
339 // Iterate by reference
340 foreach ($settings as &$setting) {
341 $name = $setting->get_ui_name();
342 if (isset($data->$name) && $data->$name != $setting->get_value()) {
343 $setting->set_value($data->$name);
344 $changes++;
345 } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
346 $setting->set_value(0);
347 $changes++;
348 }
349 }
350 }
351 }
352 // Return the number of changes the user made
353 return $changes;
354 } else {
355 return false;
356 }
357 }
358 /**
359 * Creates the backup_schema_form instance for this stage
360 *
361 * @return backup_schema_form
362 */
363 protected function initialise_stage_form() {
364 global $PAGE;
365 if ($this->stageform === null) {
366 $form = new restore_schema_form($this, $PAGE->url);
367 $tasks = $this->ui->get_tasks();
368 $content = '';
369 $courseheading = false;
370 foreach ($tasks as $task) {
371 if (!($task instanceof restore_root_task)) {
372 if (!$courseheading) {
373 // If we havn't already display a course heading to group nicely
374 $form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
375 $courseheading = true;
376 }
377 // First add each setting
378 foreach ($task->get_settings() as $setting) {
379 $form->add_setting($setting, $task);
380 }
381 // The add all the dependencies
382 foreach ($task->get_settings() as $setting) {
383 $form->add_dependencies($setting);
384 }
385 } else if ($this->ui->enforce_changed_dependencies()) {
386 // Only show these settings if dependencies changed them.
387 // Add a root settings heading to group nicely
388 $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
389 // Iterate all settings and add them to the form as a fixed
390 // setting. We only want schema settings to be editable
391 foreach ($task->get_settings() as $setting) {
392 if ($setting->get_name() != 'filename') {
393 $form->add_fixed_setting($setting);
394 }
395 }
396 }
397 }
398 $this->stageform = $form;
399 }
400 return $this->stageform;
401 }
402}
403
404/**
405 * Confirmation stage
406 *
407 * On this stage the user reviews the setting for the backup and can change the filename
408 * of the file that will be generated.
409 *
410 * @copyright 2010 Sam Hemelryk
411 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
412 */
413class restore_ui_stage_review extends restore_ui_stage {
414 /**
415 * Constructs the stage
416 * @param backup_ui $ui
417 */
418 public function __construct($ui, array $params=null) {
419 $this->stage = restore_ui::STAGE_REVIEW;
420 parent::__construct($ui, $params);
421 }
422 /**
423 * Processes the confirmation stage
424 *
425 * @param backup_moodleform $form
426 * @return int The number of changes the user made
427 */
428 public function process(base_moodleform $form = null) {
429 $form = $this->initialise_stage_form();
430 // Check it hasn't been cancelled
431 if ($form->is_cancelled()) {
432 $this->ui->cancel_backup();
433 }
434
435 $data = $form->get_data();
436 if ($data && confirm_sesskey()) {
437 return 0;
438 } else {
439 return false;
440 }
441 }
442 /**
443 * Creates the backup_confirmation_form instance this stage requires
444 *
445 * @return backup_confirmation_form
446 */
447 protected function initialise_stage_form() {
448 global $PAGE;
449 if ($this->stageform === null) {
450 // Get the form
451 $form = new restore_review_form($this, $PAGE->url);
452 $content = '';
453 $courseheading = false;
454
455 foreach ($this->ui->get_tasks() as $task) {
456 if ($task instanceof restore_root_task) {
457 // If its a backup root add a root settings heading to group nicely
458 $form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
459 } else if (!$courseheading) {
460 // we havn't already add a course heading
461 $form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
462 $courseheading = true;
463 }
464 // Iterate all settings, doesnt need to happen by reference
465 foreach ($task->get_settings() as $setting) {
466 $form->add_fixed_setting($setting);
467 }
468 }
469 $this->stageform = $form;
470 }
471 return $this->stageform;
472 }
473}
474
475/**
476 * Final stage of backup
477 *
478 * This stage is special in that it is does not make use of a form. The reason for
479 * this is the order of procession of backup at this stage.
480 * The processesion is:
481 * 1. The final stage will be intialise.
482 * 2. The confirmation stage will be processed.
483 * 3. The backup will be executed
484 * 4. The complete stage will be loaded by execution
485 * 5. The complete stage will be displayed
486 *
487 * This highlights that we neither need a form nor a display method for this stage
488 * we simply need to process.
489 *
490 * @copyright 2010 Sam Hemelryk
491 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
492 */
493class restore_ui_stage_process extends restore_ui_stage {
494
495 const SUBSTAGE_NONE = 0;
496 const SUBSTAGE_CONVERT = 1;
497 const SUBSTAGE_PRECHECKS = 2;
498
499 protected $substage = 0;
500
501 /**
502 * Constructs the final stage
503 * @param backup_ui $ui
504 */
505 public function __construct(base_ui $ui, array $params=null) {
506 $this->stage = restore_ui::STAGE_PROCESS;
507 parent::__construct($ui, $params);
508 }
509 /**
510 * Processes the final stage.
511 *
512 * In this case it checks to see if there is a sub stage that we need to display
513 * before execution, if there is we gear up to display the subpage, otherwise
514 * we return true which will lead to execution of the restore and the loading
515 * of the completed stage.
516 */
517 public function process(base_moodleform $form=null) {
518 $rc = $this->ui->get_controller();
519 if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) {
520 $this->substage = self::SUBSTAGE_CONVERT;
521 } else {
522 if ($rc->get_status() == backup::STATUS_SETTING_UI) {
523 $rc->finish_ui();
524 }
525 if ($rc->get_status() == backup::STATUS_NEED_PRECHECK && !$rc->execute_precheck(true)) {
526 $this->substage = self::SUBSTAGE_PRECHECKS;
527 }
528 }
529 return empty($this->substage);
530 }
531 /**
532 * should NEVER be called... throws an exception
533 */
534 protected function initialise_stage_form() {
535 throw new backup_ui_exception('backup_ui_must_execute_first');
536 }
537 /**
538 * should NEVER be called... throws an exception
539 */
540 public function display($renderer) {
541 global $PAGE;
542 switch ($this->substage) {
543 case self::SUBSTAGE_CONVERT :
544 echo '<h2>Need to show the conversion screens here</h2>';
545 break;
546 case self::SUBSTAGE_PRECHECKS :
547 $results = $this->ui->get_controller()->get_precheck_results();
548 echo $renderer->precheck_notices($results);
549 break;
550 default:
551 throw new restore_ui_exception('backup_ui_must_execute_first');
552 }
553 echo $renderer->continue_button(new moodle_url($PAGE->url, array('restore'=>$this->get_uniqueid(), 'stage'=>restore_ui::STAGE_PROCESS, 'substage'=>$this->substage)));
554 }
555
556 public function has_sub_stages() {
557 return true;
558 }
559}
560
561class restore_ui_stage_complete extends restore_ui_stage_process {
562 /**
563 * The results of the backup execution
564 * @var array
565 */
566 protected $results;
567 /**
568 * Constructs the complete backup stage
569 * @param backup_ui $ui
570 * @param array|null $params
571 * @param array $results
572 */
573 public function __construct(restore_ui $ui, array $params=null, array $results=null) {
574 $this->results = $results;
575 parent::__construct($ui, $params);
576 $this->stage = restore_ui::STAGE_COMPLETE;
577 }
578 /**
579 * Displays the completed backup stage.
580 *
581 * Currently this just envolves redirecting to the file browser with an
582 * appropriate message.
583 *
584 * @global core_renderer $OUTPUT
585 */
586 public function display($renderer) {
587 global $OUTPUT;
588 echo $OUTPUT->box_start();
589 echo $OUTPUT->notification(get_string('restoreexecutionsuccess', 'backup'), 'notifysuccess');
590 echo $renderer->continue_button(new moodle_url('/course/view.php', array('id'=>$this->get_ui()->get_controller()->get_courseid())));
591 echo $OUTPUT->box_end();
592 }
593}