Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
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/>. 16 17 /** 18 * restore user interface stages 19 * 20 * This file contains the classes required to manage the stages that make up the 21 * restore user interface. 22 * These will be primarily operated a {@link restore_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 */ 28 29 /** 30 * Abstract stage class 31 * 32 * This class should be extended by all restore stages (a requirement of many restore ui functions). 33 * Each stage must then define two abstract methods 34 * - process : To process the stage 35 * - initialise_stage_form : To get a restore_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 restore_ui_stage extends base_ui_stage { 42 /** 43 * Constructor 44 * @param restore_ui $ui 45 * @param array $params 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 /** 60 * This is an independent stage 61 * @return int 62 */ 63 final public function is_independent() { 64 return false; 65 } 66 67 /** 68 * No sub stages for this stage 69 * @return false 70 */ 71 public function has_sub_stages() { 72 return false; 73 } 74 75 /** 76 * The name of this stage 77 * @return string 78 */ 79 final public function get_name() { 80 return get_string('restorestage'.$this->stage, 'backup'); 81 } 82 83 /** 84 * Returns true if this is the settings stage 85 * @return bool 86 */ 87 final public function is_first_stage() { 88 return $this->stage == restore_ui::STAGE_SETTINGS; 89 } 90 } 91 92 /** 93 * Abstract class used to represent a restore stage that is indenependent. 94 * 95 * An independent stage is a judged to be so because it doesn't require, and has 96 * no use for the restore controller. 97 * 98 * @package core_backup 99 * @copyright 2010 Sam Hemelryk 100 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 101 */ 102 abstract class restore_ui_independent_stage { 103 /** 104 * @var \core\progress\base Optional progress reporter 105 */ 106 private $progressreporter; 107 108 /** 109 * Constructs the restore stage. 110 * @param int $contextid 111 */ 112 abstract public function __construct($contextid); 113 114 /** 115 * Processes the current restore stage. 116 * @return mixed 117 */ 118 abstract public function process(); 119 120 /** 121 * Displays this restore stage. 122 * @param core_backup_renderer $renderer 123 * @return mixed 124 */ 125 abstract public function display(core_backup_renderer $renderer); 126 127 /** 128 * Returns the current restore stage. 129 * @return int 130 */ 131 abstract public function get_stage(); 132 133 /** 134 * Gets the progress reporter object in use for this restore UI stage. 135 * 136 * IMPORTANT: This progress reporter is used only for UI progress that is 137 * outside the restore controller. The restore controller has its own 138 * progress reporter which is used for progress during the main restore. 139 * Use the restore controller's progress reporter to report progress during 140 * a restore operation, not this one. 141 * 142 * This extra reporter is necessary because on some restore UI screens, 143 * there are long-running tasks even though there is no restore controller 144 * in use. There is a similar function in restore_ui. but that class is not 145 * used on some stages. 146 * 147 * @return \core\progress\none 148 */ 149 public function get_progress_reporter() { 150 if (!$this->progressreporter) { 151 $this->progressreporter = new \core\progress\none(); 152 } 153 return $this->progressreporter; 154 } 155 156 /** 157 * Sets the progress reporter that will be returned by get_progress_reporter. 158 * 159 * @param \core\progress\base $progressreporter Progress reporter 160 */ 161 public function set_progress_reporter(\core\progress\base $progressreporter) { 162 $this->progressreporter = $progressreporter; 163 } 164 165 /** 166 * Gets an array of progress bar items that can be displayed through the restore renderer. 167 * @return array Array of items for the progress bar 168 */ 169 public function get_progress_bar() { 170 global $PAGE; 171 $stage = restore_ui::STAGE_COMPLETE; 172 $currentstage = $this->get_stage(); 173 $items = array(); 174 while ($stage > 0) { 175 $classes = array('backup_stage'); 176 if (floor($stage / 2) == $currentstage) { 177 $classes[] = 'backup_stage_next'; 178 } else if ($stage == $currentstage) { 179 $classes[] = 'backup_stage_current'; 180 } else if ($stage < $currentstage) { 181 $classes[] = 'backup_stage_complete'; 182 } 183 $item = array('text' => strlen(decbin($stage)).'. '.get_string('restorestage'.$stage, 'backup'), 'class' => join(' ', $classes)); 184 if ($stage < $currentstage && $currentstage < restore_ui::STAGE_COMPLETE) { 185 // By default you can't go back to independent stages, if that changes in the future uncomment the next line. 186 // $item['link'] = new moodle_url($PAGE->url, array('restore' => $this->get_restoreid(), 'stage' => $stage)); 187 } 188 array_unshift($items, $item); 189 $stage = floor($stage / 2); 190 } 191 return $items; 192 } 193 194 /** 195 * Returns the restore stage name. 196 * @return string 197 */ 198 abstract public function get_stage_name(); 199 200 /** 201 * Obviously true 202 * @return true 203 */ 204 final public function is_independent() { 205 return true; 206 } 207 208 /** 209 * Handles the destruction of this object. 210 */ 211 public function destroy() { 212 // Nothing to destroy here!. 213 } 214 } 215 216 /** 217 * The confirmation stage. 218 * 219 * This is the first stage, it is independent. 220 * 221 * @package core_backup 222 * @copyright 2010 Sam Hemelryk 223 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 224 */ 225 class restore_ui_stage_confirm extends restore_ui_independent_stage implements file_progress { 226 227 /** 228 * The context ID. 229 * @var int 230 */ 231 protected $contextid; 232 233 /** 234 * The file name. 235 * @var string 236 */ 237 protected $filename = null; 238 239 /** 240 * The file path. 241 * @var string 242 */ 243 protected $filepath = null; 244 245 /** 246 * @var string Content hash of archive file to restore (if specified by hash) 247 */ 248 protected $contenthash = null; 249 250 /** 251 * @var string Pathname hash of stored_file object to restore 252 */ 253 protected $pathnamehash = null; 254 255 /** 256 * @var array 257 */ 258 protected $details; 259 260 /** 261 * @var bool True if we have started reporting progress 262 */ 263 protected $startedprogress = false; 264 265 /** 266 * Constructor 267 * @param int $contextid 268 * @throws coding_exception 269 */ 270 public function __construct($contextid) { 271 $this->contextid = $contextid; 272 $this->filename = optional_param('filename', null, PARAM_FILE); 273 if ($this->filename === null) { 274 // Identify file object by its pathname hash. 275 $this->pathnamehash = required_param('pathnamehash', PARAM_ALPHANUM); 276 277 // The file content hash is also passed for security; users 278 // cannot guess the content hash (unless they know the file contents), 279 // so this guarantees that either the system generated this link or 280 // else the user has access to the restore archive anyhow. 281 $this->contenthash = required_param('contenthash', PARAM_ALPHANUM); 282 } 283 } 284 285 /** 286 * Processes this restore stage 287 * @return bool 288 * @throws restore_ui_exception 289 */ 290 public function process() { 291 $backuptempdir = make_backup_temp_directory(''); 292 if ($this->filename) { 293 $archivepath = $backuptempdir . '/' . $this->filename; 294 if (!file_exists($archivepath)) { 295 throw new restore_ui_exception('invalidrestorefile'); 296 } 297 $outcome = $this->extract_file_to_dir($archivepath); 298 if ($outcome) { 299 fulldelete($archivepath); 300 } 301 } else { 302 $fs = get_file_storage(); 303 $storedfile = $fs->get_file_by_hash($this->pathnamehash); 304 if (!$storedfile || $storedfile->get_contenthash() !== $this->contenthash) { 305 throw new restore_ui_exception('invalidrestorefile'); 306 } 307 $outcome = $this->extract_file_to_dir($storedfile); 308 } 309 return $outcome; 310 } 311 312 /** 313 * Extracts the file. 314 * 315 * @param string|stored_file $source Archive file to extract 316 * @return bool 317 */ 318 protected function extract_file_to_dir($source) { 319 global $USER; 320 321 $this->filepath = restore_controller::get_tempdir_name($this->contextid, $USER->id); 322 $backuptempdir = make_backup_temp_directory('', false); 323 324 $fb = get_file_packer('application/vnd.moodle.backup'); 325 $result = $fb->extract_to_pathname($source, 326 $backuptempdir . '/' . $this->filepath . '/', null, $this); 327 328 // If any progress happened, end it. 329 if ($this->startedprogress) { 330 $this->get_progress_reporter()->end_progress(); 331 } 332 return $result; 333 } 334 335 /** 336 * Implementation for file_progress interface to display unzip progress. 337 * 338 * @param int $progress Current progress 339 * @param int $max Max value 340 */ 341 public function progress($progress = file_progress::INDETERMINATE, $max = file_progress::INDETERMINATE) { 342 $reporter = $this->get_progress_reporter(); 343 344 // Start tracking progress if necessary. 345 if (!$this->startedprogress) { 346 $reporter->start_progress('extract_file_to_dir', 347 ($max == file_progress::INDETERMINATE) ? \core\progress\base::INDETERMINATE : $max); 348 $this->startedprogress = true; 349 } 350 351 // Pass progress through to whatever handles it. 352 $reporter->progress( 353 ($progress == file_progress::INDETERMINATE) ? \core\progress\base::INDETERMINATE : $progress); 354 } 355 356 /** 357 * Renders the confirmation stage screen 358 * 359 * @param core_backup_renderer $renderer renderer instance to use 360 * @return string HTML code 361 */ 362 public function display(core_backup_renderer $renderer) { 363 364 $prevstageurl = new moodle_url('/backup/restorefile.php', array('contextid' => $this->contextid)); 365 $nextstageurl = new moodle_url('/backup/restore.php', array( 366 'contextid' => $this->contextid, 367 'filepath' => $this->filepath, 368 'stage' => restore_ui::STAGE_DESTINATION)); 369 370 $format = backup_general_helper::detect_backup_format($this->filepath); 371 372 if ($format === backup::FORMAT_UNKNOWN) { 373 // Unknown format - we can't do anything here. 374 return $renderer->backup_details_unknown($prevstageurl); 375 376 } else if ($format !== backup::FORMAT_MOODLE) { 377 // Non-standard format to be converted. 378 $details = array('format' => $format, 'type' => backup::TYPE_1COURSE); // todo type to be returned by a converter 379 return $renderer->backup_details_nonstandard($nextstageurl, $details); 380 381 } else { 382 // Standard MBZ backup, let us get information from it and display. 383 $this->details = backup_general_helper::get_backup_information($this->filepath); 384 return $renderer->backup_details($this->details, $nextstageurl); 385 } 386 } 387 388 /** 389 * The restore stage name. 390 * @return string 391 * @throws coding_exception 392 */ 393 public function get_stage_name() { 394 return get_string('restorestage'.restore_ui::STAGE_CONFIRM, 'backup'); 395 } 396 397 /** 398 * The restore stage this class is for. 399 * @return int 400 */ 401 public function get_stage() { 402 return restore_ui::STAGE_CONFIRM; 403 } 404 } 405 406 /** 407 * This is the destination stage. 408 * 409 * This stage is the second stage and is also independent 410 * 411 * @package core_backup 412 * @copyright 2010 Sam Hemelryk 413 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 414 */ 415 class restore_ui_stage_destination extends restore_ui_independent_stage { 416 417 /** 418 * The context ID. 419 * @var int 420 */ 421 protected $contextid; 422 423 /** 424 * The backup file path. 425 * @var mixed|null 426 */ 427 protected $filepath = null; 428 429 /** 430 * The course ID. 431 * @var null 432 */ 433 protected $courseid = null; 434 435 /** 436 * The restore target. One of backup::TARGET_NEW 437 * @var int 438 */ 439 protected $target = backup::TARGET_NEW_COURSE; 440 441 /** 442 * The course search component. 443 * @var null|restore_course_search 444 */ 445 protected $coursesearch = null; 446 447 /** 448 * The category search component. 449 * @var null|restore_category_search 450 */ 451 protected $categorysearch = null; 452 453 /** 454 * Constructs the destination stage. 455 * @param int $contextid 456 * @throws coding_exception 457 */ 458 public function __construct($contextid) { 459 global $PAGE; 460 $this->contextid = $contextid; 461 $this->filepath = required_param('filepath', PARAM_ALPHANUM); 462 $url = new moodle_url($PAGE->url, array( 463 'filepath' => $this->filepath, 464 'contextid' => $this->contextid, 465 'stage' => restore_ui::STAGE_DESTINATION)); 466 // The context level can be course category, course or module. We need to make sure that we always use correct one. 467 $context = context::instance_by_id($contextid); 468 if ($context->contextlevel != CONTEXT_COURSE && $coursecontext = $context->get_course_context(false)) { 469 $context = $coursecontext; 470 } 471 $this->coursesearch = new restore_course_search(array('url' => $url), $context->instanceid); 472 $this->categorysearch = new restore_category_search(array('url' => $url)); 473 } 474 475 /** 476 * Processes the destination stage. 477 * @return bool 478 * @throws coding_exception 479 * @throws restore_ui_exception 480 */ 481 public function process() { 482 global $DB; 483 $filepathdir = make_backup_temp_directory($this->filepath, false); 484 if (!file_exists($filepathdir) || !is_dir($filepathdir)) { 485 throw new restore_ui_exception('invalidrestorepath'); 486 } 487 if (optional_param('searchcourses', false, PARAM_BOOL)) { 488 return false; 489 } 490 $this->target = optional_param('target', backup::TARGET_NEW_COURSE, PARAM_INT); 491 $targetid = optional_param('targetid', null, PARAM_INT); 492 if (!is_null($this->target) && !is_null($targetid) && confirm_sesskey()) { 493 if ($this->target == backup::TARGET_NEW_COURSE) { 494 list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'), get_string('restoringcourseshortname', 'backup')); 495 $this->courseid = restore_dbops::create_new_course($fullname, $shortname, $targetid); 496 } else { 497 $this->courseid = $targetid; 498 } 499 return ($DB->record_exists('course', array('id' => $this->courseid))); 500 } 501 return false; 502 } 503 504 /** 505 * Renders the destination stage screen 506 * 507 * @param core_backup_renderer $renderer renderer instance to use 508 * @return string HTML code 509 */ 510 public function display(core_backup_renderer $renderer) { 511 512 $format = backup_general_helper::detect_backup_format($this->filepath); 513 514 if ($format === backup::FORMAT_MOODLE) { 515 // Standard Moodle 2 format, let use get the type of the backup. 516 $details = backup_general_helper::get_backup_information($this->filepath); 517 if ($details->type === backup::TYPE_1COURSE) { 518 $wholecourse = true; 519 } else { 520 $wholecourse = false; 521 } 522 523 } else { 524 // Non-standard format to be converted. We assume it contains the 525 // whole course for now. However, in the future there might be a callback 526 // to the installed converters. 527 $wholecourse = true; 528 } 529 530 $nextstageurl = new moodle_url('/backup/restore.php', array( 531 'contextid' => $this->contextid, 532 'filepath' => $this->filepath, 533 'stage' => restore_ui::STAGE_SETTINGS)); 534 $context = context::instance_by_id($this->contextid); 535 536 if ($context->contextlevel == CONTEXT_COURSE and has_capability('moodle/restore:restorecourse', $context)) { 537 $currentcourse = $context->instanceid; 538 } else { 539 $currentcourse = false; 540 } 541 542 return $renderer->course_selector($nextstageurl, $wholecourse, $this->categorysearch, $this->coursesearch, $currentcourse); 543 } 544 545 /** 546 * Returns the stage name. 547 * @return string 548 * @throws coding_exception 549 */ 550 public function get_stage_name() { 551 return get_string('restorestage'.restore_ui::STAGE_DESTINATION, 'backup'); 552 } 553 554 /** 555 * Returns the backup file path 556 * @return mixed|null 557 */ 558 public function get_filepath() { 559 return $this->filepath; 560 } 561 562 /** 563 * Returns the course id. 564 * @return null 565 */ 566 public function get_course_id() { 567 return $this->courseid; 568 } 569 570 /** 571 * Returns the current restore stage 572 * @return int 573 */ 574 public function get_stage() { 575 return restore_ui::STAGE_DESTINATION; 576 } 577 578 /** 579 * Returns the target for this restore. 580 * One of backup::TARGET_* 581 * @return int 582 */ 583 public function get_target() { 584 return $this->target; 585 } 586 } 587 588 /** 589 * This stage is the settings stage. 590 * 591 * This stage is the third stage, it is dependent on a restore controller and 592 * is the first stage as such. 593 * 594 * @package core_backup 595 * @copyright 2010 Sam Hemelryk 596 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 597 */ 598 class restore_ui_stage_settings extends restore_ui_stage { 599 /** 600 * Initial restore stage constructor 601 * @param restore_ui $ui 602 * @param array $params 603 */ 604 public function __construct(restore_ui $ui, array $params = null) { 605 $this->stage = restore_ui::STAGE_SETTINGS; 606 parent::__construct($ui, $params); 607 } 608 609 /** 610 * Process the settings stage. 611 * 612 * @param base_moodleform $form 613 * @return bool|int 614 */ 615 public function process(base_moodleform $form = null) { 616 $form = $this->initialise_stage_form(); 617 618 if ($form->is_cancelled()) { 619 $this->ui->cancel_process(); 620 } 621 622 $data = $form->get_data(); 623 if ($data && confirm_sesskey()) { 624 $tasks = $this->ui->get_tasks(); 625 $changes = 0; 626 foreach ($tasks as &$task) { 627 // We are only interesting in the backup root task for this stage. 628 if ($task instanceof restore_root_task || $task instanceof restore_course_task) { 629 // Get all settings into a var so we can iterate by reference. 630 $settings = $task->get_settings(); 631 foreach ($settings as &$setting) { 632 $name = $setting->get_ui_name(); 633 if (isset($data->$name) && $data->$name != $setting->get_value()) { 634 $setting->set_value($data->$name); 635 $changes++; 636 } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) { 637 $setting->set_value(0); 638 $changes++; 639 } 640 } 641 } 642 } 643 // Return the number of changes the user made. 644 return $changes; 645 } else { 646 return false; 647 } 648 } 649 650 /** 651 * Initialise the stage form. 652 * 653 * @return backup_moodleform|base_moodleform|restore_settings_form 654 * @throws coding_exception 655 */ 656 protected function initialise_stage_form() { 657 global $PAGE; 658 if ($this->stageform === null) { 659 $form = new restore_settings_form($this, $PAGE->url); 660 // Store as a variable so we can iterate by reference. 661 $tasks = $this->ui->get_tasks(); 662 $headingprinted = false; 663 // Iterate all tasks by reference. 664 foreach ($tasks as &$task) { 665 // For the initial stage we are only interested in the root settings. 666 if ($task instanceof restore_root_task) { 667 if (!$headingprinted) { 668 $form->add_heading('rootsettings', get_string('restorerootsettings', 'backup')); 669 $headingprinted = true; 670 } 671 $settings = $task->get_settings(); 672 // First add all settings except the filename setting. 673 foreach ($settings as &$setting) { 674 if ($setting->get_name() == 'filename') { 675 continue; 676 } 677 $form->add_setting($setting, $task); 678 } 679 // Then add all dependencies. 680 foreach ($settings as &$setting) { 681 if ($setting->get_name() == 'filename') { 682 continue; 683 } 684 $form->add_dependencies($setting); 685 } 686 } 687 } 688 $this->stageform = $form; 689 } 690 // Return the form. 691 return $this->stageform; 692 } 693 } 694 695 /** 696 * Schema stage of backup process 697 * 698 * During the schema stage the user is required to set the settings that relate 699 * to the area that they are backing up as well as its children. 700 * 701 * @package core_backup 702 * @copyright 2010 Sam Hemelryk 703 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 704 */ 705 class restore_ui_stage_schema extends restore_ui_stage { 706 /** 707 * @var int Maximum number of settings to add to form at once 708 */ 709 const MAX_SETTINGS_BATCH = 1000; 710 711 /** 712 * Schema stage constructor 713 * @param restore_ui $ui 714 * @param array $params 715 */ 716 public function __construct(restore_ui $ui, array $params = null) { 717 $this->stage = restore_ui::STAGE_SCHEMA; 718 parent::__construct($ui, $params); 719 } 720 721 /** 722 * Processes the schema stage 723 * 724 * @param base_moodleform $form 725 * @return int The number of changes the user made 726 */ 727 public function process(base_moodleform $form = null) { 728 $form = $this->initialise_stage_form(); 729 // Check it wasn't cancelled. 730 if ($form->is_cancelled()) { 731 $this->ui->cancel_process(); 732 } 733 734 // Check it has been submit. 735 $data = $form->get_data(); 736 if ($data && confirm_sesskey()) { 737 // Get the tasks into a var so we can iterate by reference. 738 $tasks = $this->ui->get_tasks(); 739 $changes = 0; 740 // Iterate all tasks by reference. 741 foreach ($tasks as &$task) { 742 // We are only interested in schema settings. 743 if (!($task instanceof restore_root_task)) { 744 // Store as a variable so we can iterate by reference. 745 $settings = $task->get_settings(); 746 // Iterate by reference. 747 foreach ($settings as &$setting) { 748 $name = $setting->get_ui_name(); 749 if (isset($data->$name) && $data->$name != $setting->get_value()) { 750 $setting->set_value($data->$name); 751 $changes++; 752 } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) { 753 $setting->set_value(0); 754 $changes++; 755 } 756 } 757 } 758 } 759 // Return the number of changes the user made. 760 return $changes; 761 } else { 762 return false; 763 } 764 } 765 766 /** 767 * Creates the backup_schema_form instance for this stage 768 * 769 * @return backup_schema_form 770 */ 771 protected function initialise_stage_form() { 772 global $PAGE; 773 if ($this->stageform === null) { 774 $form = new restore_schema_form($this, $PAGE->url); 775 $tasks = $this->ui->get_tasks(); 776 $courseheading = false; 777 778 // Track progress through each stage. 779 $progress = $this->ui->get_progress_reporter(); 780 $progress->start_progress('Initialise schema stage form', 3); 781 782 $progress->start_progress('', count($tasks)); 783 $done = 1; 784 $allsettings = array(); 785 foreach ($tasks as $task) { 786 if (!($task instanceof restore_root_task)) { 787 if (!$courseheading) { 788 // If we haven't already display a course heading to group nicely. 789 $form->add_heading('coursesettings', get_string('coursesettings', 'backup')); 790 $courseheading = true; 791 } 792 // Put each setting into an array of settings to add. Adding 793 // a setting individually is a very slow operation, so we add. 794 // them all in a batch later on. 795 foreach ($task->get_settings() as $setting) { 796 $allsettings[] = array($setting, $task); 797 } 798 } else if ($this->ui->enforce_changed_dependencies()) { 799 // Only show these settings if dependencies changed them. 800 // Add a root settings heading to group nicely. 801 $form->add_heading('rootsettings', get_string('rootsettings', 'backup')); 802 // Iterate all settings and add them to the form as a fixed 803 // setting. We only want schema settings to be editable. 804 foreach ($task->get_settings() as $setting) { 805 if ($setting->get_name() != 'filename') { 806 $form->add_fixed_setting($setting, $task); 807 } 808 } 809 } 810 // Update progress. 811 $progress->progress($done++); 812 } 813 $progress->end_progress(); 814 815 // Add settings for tasks in batches of up to 1000. Adding settings 816 // in larger batches improves performance, but if it takes too long, 817 // we won't be able to update the progress bar so the backup might. 818 // time out. 1000 is chosen to balance this. 819 $numsettings = count($allsettings); 820 $progress->start_progress('', ceil($numsettings / self::MAX_SETTINGS_BATCH)); 821 $start = 0; 822 $done = 1; 823 while ($start < $numsettings) { 824 $length = min(self::MAX_SETTINGS_BATCH, $numsettings - $start); 825 $form->add_settings(array_slice($allsettings, $start, $length)); 826 $start += $length; 827 $progress->progress($done++); 828 } 829 $progress->end_progress(); 830 831 // Add the dependencies for all the settings. 832 $progress->start_progress('', count($allsettings)); 833 $done = 1; 834 foreach ($allsettings as $settingtask) { 835 $form->add_dependencies($settingtask[0]); 836 $progress->progress($done++); 837 } 838 $progress->end_progress(); 839 840 $progress->end_progress(); 841 $this->stageform = $form; 842 } 843 return $this->stageform; 844 } 845 } 846 847 /** 848 * Confirmation stage 849 * 850 * On this stage the user reviews the setting for the backup and can change the filename 851 * of the file that will be generated. 852 * 853 * @package core_backup 854 * @copyright 2010 Sam Hemelryk 855 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 856 */ 857 class restore_ui_stage_review extends restore_ui_stage { 858 859 /** 860 * Constructs the stage 861 * @param restore_ui $ui 862 * @param array $params 863 */ 864 public function __construct($ui, array $params = null) { 865 $this->stage = restore_ui::STAGE_REVIEW; 866 parent::__construct($ui, $params); 867 } 868 869 /** 870 * Processes the confirmation stage 871 * 872 * @param base_moodleform $form 873 * @return int The number of changes the user made 874 */ 875 public function process(base_moodleform $form = null) { 876 $form = $this->initialise_stage_form(); 877 // Check it hasn't been cancelled. 878 if ($form->is_cancelled()) { 879 $this->ui->cancel_process(); 880 } 881 882 $data = $form->get_data(); 883 if ($data && confirm_sesskey()) { 884 return 0; 885 } else { 886 return false; 887 } 888 } 889 /** 890 * Creates the backup_confirmation_form instance this stage requires 891 * 892 * @return backup_confirmation_form 893 */ 894 protected function initialise_stage_form() { 895 global $PAGE; 896 if ($this->stageform === null) { 897 // Get the form. 898 $form = new restore_review_form($this, $PAGE->url); 899 $content = ''; 900 $courseheading = false; 901 902 $progress = $this->ui->get_progress_reporter(); 903 $tasks = $this->ui->get_tasks(); 904 $progress->start_progress('initialise_stage_form', count($tasks)); 905 $done = 1; 906 foreach ($tasks as $task) { 907 if ($task instanceof restore_root_task) { 908 // If its a backup root add a root settings heading to group nicely. 909 $form->add_heading('rootsettings', get_string('restorerootsettings', 'backup')); 910 } else if (!$courseheading) { 911 // We haven't already add a course heading. 912 $form->add_heading('coursesettings', get_string('coursesettings', 'backup')); 913 $courseheading = true; 914 } 915 // Iterate all settings, doesnt need to happen by reference. 916 foreach ($task->get_settings() as $setting) { 917 $form->add_fixed_setting($setting, $task); 918 } 919 // Update progress. 920 $progress->progress($done++); 921 } 922 $progress->end_progress(); 923 $this->stageform = $form; 924 } 925 return $this->stageform; 926 } 927 } 928 929 /** 930 * Final stage of backup 931 * 932 * This stage is special in that it is does not make use of a form. The reason for 933 * this is the order of procession of backup at this stage. 934 * The processesion is: 935 * 1. The final stage will be intialise. 936 * 2. The confirmation stage will be processed. 937 * 3. The backup will be executed 938 * 4. The complete stage will be loaded by execution 939 * 5. The complete stage will be displayed 940 * 941 * This highlights that we neither need a form nor a display method for this stage 942 * we simply need to process. 943 * 944 * @package core_backup 945 * @copyright 2010 Sam Hemelryk 946 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 947 */ 948 class restore_ui_stage_process extends restore_ui_stage { 949 950 /** 951 * There is no substage required. 952 */ 953 const SUBSTAGE_NONE = 0; 954 955 /** 956 * The prechecks substage is required/the current substage. 957 */ 958 const SUBSTAGE_PRECHECKS = 2; 959 960 /** 961 * The current substage. 962 * @var int 963 */ 964 protected $substage = 0; 965 966 /** 967 * Constructs the final stage 968 * @param base_ui $ui 969 * @param array $params 970 */ 971 public function __construct(base_ui $ui, array $params = null) { 972 $this->stage = restore_ui::STAGE_PROCESS; 973 parent::__construct($ui, $params); 974 } 975 /** 976 * Processes the final stage. 977 * 978 * In this case it checks to see if there is a sub stage that we need to display 979 * before execution, if there is we gear up to display the subpage, otherwise 980 * we return true which will lead to execution of the restore and the loading 981 * of the completed stage. 982 * 983 * @param base_moodleform $form 984 */ 985 public function process(base_moodleform $form = null) { 986 if (optional_param('cancel', false, PARAM_BOOL)) { 987 redirect(new moodle_url('/course/view.php', array('id' => $this->get_ui()->get_controller()->get_courseid()))); 988 } 989 990 // First decide whether a substage is needed. 991 $rc = $this->ui->get_controller(); 992 if ($rc->get_status() == backup::STATUS_SETTING_UI) { 993 $rc->finish_ui(); 994 } 995 if ($rc->get_status() == backup::STATUS_NEED_PRECHECK) { 996 if (!$rc->precheck_executed()) { 997 $rc->execute_precheck(true); 998 } 999 $results = $rc->get_precheck_results(); 1000 if (!empty($results)) { 1001 $this->substage = self::SUBSTAGE_PRECHECKS; 1002 } 1003 } 1004 1005 $substage = optional_param('substage', null, PARAM_INT); 1006 if (empty($this->substage) && !empty($substage)) { 1007 $this->substage = $substage; 1008 // Now check whether that substage has already been submit. 1009 if ($this->substage == self::SUBSTAGE_PRECHECKS && optional_param('sesskey', null, PARAM_RAW) == sesskey()) { 1010 $info = $rc->get_info(); 1011 if (!empty($info->role_mappings->mappings)) { 1012 foreach ($info->role_mappings->mappings as $key => &$mapping) { 1013 $mapping->targetroleid = optional_param('mapping'.$key, $mapping->targetroleid, PARAM_INT); 1014 } 1015 $info->role_mappings->modified = true; 1016 } 1017 // We've processed the substage now setting it back to none so we 1018 // can move to the next stage. 1019 $this->substage = self::SUBSTAGE_NONE; 1020 } 1021 } 1022 1023 return empty($this->substage); 1024 } 1025 /** 1026 * should NEVER be called... throws an exception 1027 */ 1028 protected function initialise_stage_form() { 1029 throw new backup_ui_exception('backup_ui_must_execute_first'); 1030 } 1031 1032 /** 1033 * Renders the process stage screen 1034 * 1035 * @throws restore_ui_exception 1036 * @param core_backup_renderer $renderer renderer instance to use 1037 * @return string HTML code 1038 */ 1039 public function display(core_backup_renderer $renderer) { 1040 global $PAGE; 1041 1042 $html = ''; 1043 $haserrors = false; 1044 $url = new moodle_url($PAGE->url, array( 1045 'restore' => $this->get_uniqueid(), 1046 'stage' => restore_ui::STAGE_PROCESS, 1047 'substage' => $this->substage, 1048 'sesskey' => sesskey())); 1049 $html .= html_writer::start_tag('form', array( 1050 'action' => $url->out_omit_querystring(), 1051 'class' => 'backup-restore', 1052 'enctype' => 'application/x-www-form-urlencoded', // Enforce compatibility with our max_input_vars hack. 1053 'method' => 'post')); 1054 foreach ($url->params() as $name => $value) { 1055 $html .= html_writer::empty_tag('input', array( 1056 'type' => 'hidden', 1057 'name' => $name, 1058 'value' => $value)); 1059 } 1060 switch ($this->substage) { 1061 case self::SUBSTAGE_PRECHECKS : 1062 $results = $this->ui->get_controller()->get_precheck_results(); 1063 $info = $this->ui->get_controller()->get_info(); 1064 $haserrors = (!empty($results['errors'])); 1065 $html .= $renderer->precheck_notices($results); 1066 if (!empty($info->role_mappings->mappings)) { 1067 $context = context_course::instance($this->ui->get_controller()->get_courseid()); 1068 $assignableroles = get_assignable_roles($context, ROLENAME_ALIAS, false); 1069 1070 // Get current role mappings. 1071 $currentroles = role_fix_names(get_all_roles(), $context); 1072 // Get backup role mappings. 1073 $rolemappings = $info->role_mappings->mappings; 1074 1075 array_map(function($rolemapping) use ($currentroles) { 1076 foreach ($currentroles as $role) { 1077 // Find matching archetype to determine the backup's shortname for label display. 1078 if ($rolemapping->archetype == $role->archetype) { 1079 $rolemapping->name = $rolemapping->shortname; 1080 break; 1081 } 1082 } 1083 if ($rolemapping->name == null) { 1084 $rolemapping->name = get_string('undefinedrolemapping', 'backup', $rolemapping->archetype); 1085 } 1086 }, $rolemappings); 1087 1088 $html .= $renderer->role_mappings($rolemappings, $assignableroles); 1089 } 1090 break; 1091 default: 1092 throw new restore_ui_exception('backup_ui_must_execute_first'); 1093 } 1094 $html .= $renderer->substage_buttons($haserrors); 1095 $html .= html_writer::end_tag('form'); 1096 1097 return $html; 1098 } 1099 1100 /** 1101 * Returns true if this stage can have sub-stages. 1102 * @return bool|false 1103 */ 1104 public function has_sub_stages() { 1105 return true; 1106 } 1107 } 1108 1109 /** 1110 * This is the completed stage. 1111 * 1112 * Once this is displayed there is nothing more to do. 1113 * 1114 * @package core_backup 1115 * @copyright 2010 Sam Hemelryk 1116 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1117 */ 1118 class restore_ui_stage_complete extends restore_ui_stage_process { 1119 1120 /** 1121 * The results of the backup execution 1122 * @var array 1123 */ 1124 protected $results; 1125 1126 /** 1127 * Constructs the complete backup stage 1128 * @param restore_ui $ui 1129 * @param array $params 1130 * @param array $results 1131 */ 1132 public function __construct(restore_ui $ui, array $params = null, array $results = null) { 1133 $this->results = $results; 1134 parent::__construct($ui, $params); 1135 $this->stage = restore_ui::STAGE_COMPLETE; 1136 } 1137 1138 /** 1139 * Displays the completed backup stage. 1140 * 1141 * Currently this just envolves redirecting to the file browser with an 1142 * appropriate message. 1143 * 1144 * @param core_backup_renderer $renderer 1145 * @return string HTML code to echo 1146 */ 1147 public function display(core_backup_renderer $renderer) { 1148 1149 $html = ''; 1150 if (!empty($this->results['file_aliases_restore_failures'])) { 1151 $html .= $renderer->box_start('generalbox filealiasesfailures'); 1152 $html .= $renderer->heading_with_help(get_string('filealiasesrestorefailures', 'core_backup'), 1153 'filealiasesrestorefailures', 'core_backup'); 1154 $html .= $renderer->container(get_string('filealiasesrestorefailuresinfo', 'core_backup')); 1155 $html .= $renderer->container_start('aliaseslist'); 1156 $html .= html_writer::start_tag('ul'); 1157 foreach ($this->results['file_aliases_restore_failures'] as $alias) { 1158 $html .= html_writer::tag('li', s($alias)); 1159 } 1160 $html .= html_writer::end_tag('ul'); 1161 $html .= $renderer->container_end(); 1162 $html .= $renderer->box_end(); 1163 } 1164 $html .= $renderer->box_start(); 1165 if (array_key_exists('file_missing_in_backup', $this->results)) { 1166 $html .= $renderer->notification(get_string('restorefileweremissing', 'backup'), 'notifyproblem'); 1167 } 1168 $html .= $renderer->notification(get_string('restoreexecutionsuccess', 'backup'), 'notifysuccess'); 1169 1170 $courseurl = course_get_url($this->get_ui()->get_controller()->get_courseid()); 1171 $html .= $renderer->continue_button($courseurl, 'get'); 1172 1173 $html .= $renderer->box_end(); 1174 1175 return $html; 1176 } 1177 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body