Differences Between: [Versions 310 and 402] [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 $this->coursesearch = new restore_course_search(array('url' => $url), context::instance_by_id($contextid)->instanceid); 467 $this->categorysearch = new restore_category_search(array('url' => $url)); 468 } 469 470 /** 471 * Processes the destination stage. 472 * @return bool 473 * @throws coding_exception 474 * @throws restore_ui_exception 475 */ 476 public function process() { 477 global $DB; 478 $filepathdir = make_backup_temp_directory($this->filepath, false); 479 if (!file_exists($filepathdir) || !is_dir($filepathdir)) { 480 throw new restore_ui_exception('invalidrestorepath'); 481 } 482 if (optional_param('searchcourses', false, PARAM_BOOL)) { 483 return false; 484 } 485 $this->target = optional_param('target', backup::TARGET_NEW_COURSE, PARAM_INT); 486 $targetid = optional_param('targetid', null, PARAM_INT); 487 if (!is_null($this->target) && !is_null($targetid) && confirm_sesskey()) { 488 if ($this->target == backup::TARGET_NEW_COURSE) { 489 list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'), get_string('restoringcourseshortname', 'backup')); 490 $this->courseid = restore_dbops::create_new_course($fullname, $shortname, $targetid); 491 } else { 492 $this->courseid = $targetid; 493 } 494 return ($DB->record_exists('course', array('id' => $this->courseid))); 495 } 496 return false; 497 } 498 499 /** 500 * Renders the destination stage screen 501 * 502 * @param core_backup_renderer $renderer renderer instance to use 503 * @return string HTML code 504 */ 505 public function display(core_backup_renderer $renderer) { 506 507 $format = backup_general_helper::detect_backup_format($this->filepath); 508 509 if ($format === backup::FORMAT_MOODLE) { 510 // Standard Moodle 2 format, let use get the type of the backup. 511 $details = backup_general_helper::get_backup_information($this->filepath); 512 if ($details->type === backup::TYPE_1COURSE) { 513 $wholecourse = true; 514 } else { 515 $wholecourse = false; 516 } 517 518 } else { 519 // Non-standard format to be converted. We assume it contains the 520 // whole course for now. However, in the future there might be a callback 521 // to the installed converters. 522 $wholecourse = true; 523 } 524 525 $nextstageurl = new moodle_url('/backup/restore.php', array( 526 'contextid' => $this->contextid, 527 'filepath' => $this->filepath, 528 'stage' => restore_ui::STAGE_SETTINGS)); 529 $context = context::instance_by_id($this->contextid); 530 531 if ($context->contextlevel == CONTEXT_COURSE and has_capability('moodle/restore:restorecourse', $context)) { 532 $currentcourse = $context->instanceid; 533 } else { 534 $currentcourse = false; 535 } 536 537 return $renderer->course_selector($nextstageurl, $wholecourse, $this->categorysearch, $this->coursesearch, $currentcourse); 538 } 539 540 /** 541 * Returns the stage name. 542 * @return string 543 * @throws coding_exception 544 */ 545 public function get_stage_name() { 546 return get_string('restorestage'.restore_ui::STAGE_DESTINATION, 'backup'); 547 } 548 549 /** 550 * Returns the backup file path 551 * @return mixed|null 552 */ 553 public function get_filepath() { 554 return $this->filepath; 555 } 556 557 /** 558 * Returns the course id. 559 * @return null 560 */ 561 public function get_course_id() { 562 return $this->courseid; 563 } 564 565 /** 566 * Returns the current restore stage 567 * @return int 568 */ 569 public function get_stage() { 570 return restore_ui::STAGE_DESTINATION; 571 } 572 573 /** 574 * Returns the target for this restore. 575 * One of backup::TARGET_* 576 * @return int 577 */ 578 public function get_target() { 579 return $this->target; 580 } 581 } 582 583 /** 584 * This stage is the settings stage. 585 * 586 * This stage is the third stage, it is dependent on a restore controller and 587 * is the first stage as such. 588 * 589 * @package core_backup 590 * @copyright 2010 Sam Hemelryk 591 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 592 */ 593 class restore_ui_stage_settings extends restore_ui_stage { 594 /** 595 * Initial restore stage constructor 596 * @param restore_ui $ui 597 * @param array $params 598 */ 599 public function __construct(restore_ui $ui, array $params = null) { 600 $this->stage = restore_ui::STAGE_SETTINGS; 601 parent::__construct($ui, $params); 602 } 603 604 /** 605 * Process the settings stage. 606 * 607 * @param base_moodleform $form 608 * @return bool|int 609 */ 610 public function process(base_moodleform $form = null) { 611 $form = $this->initialise_stage_form(); 612 613 if ($form->is_cancelled()) { 614 $this->ui->cancel_process(); 615 } 616 617 $data = $form->get_data(); 618 if ($data && confirm_sesskey()) { 619 $tasks = $this->ui->get_tasks(); 620 $changes = 0; 621 foreach ($tasks as &$task) { 622 // We are only interesting in the backup root task for this stage. 623 if ($task instanceof restore_root_task || $task instanceof restore_course_task) { 624 // Get all settings into a var so we can iterate by reference. 625 $settings = $task->get_settings(); 626 foreach ($settings as &$setting) { 627 $name = $setting->get_ui_name(); 628 if (isset($data->$name) && $data->$name != $setting->get_value()) { 629 $setting->set_value($data->$name); 630 $changes++; 631 } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) { 632 $setting->set_value(0); 633 $changes++; 634 } 635 } 636 } 637 } 638 // Return the number of changes the user made. 639 return $changes; 640 } else { 641 return false; 642 } 643 } 644 645 /** 646 * Initialise the stage form. 647 * 648 * @return backup_moodleform|base_moodleform|restore_settings_form 649 * @throws coding_exception 650 */ 651 protected function initialise_stage_form() { 652 global $PAGE; 653 if ($this->stageform === null) { 654 $form = new restore_settings_form($this, $PAGE->url); 655 // Store as a variable so we can iterate by reference. 656 $tasks = $this->ui->get_tasks(); 657 $headingprinted = false; 658 // Iterate all tasks by reference. 659 foreach ($tasks as &$task) { 660 // For the initial stage we are only interested in the root settings. 661 if ($task instanceof restore_root_task) { 662 if (!$headingprinted) { 663 $form->add_heading('rootsettings', get_string('restorerootsettings', 'backup')); 664 $headingprinted = true; 665 } 666 $settings = $task->get_settings(); 667 // First add all settings except the filename setting. 668 foreach ($settings as &$setting) { 669 if ($setting->get_name() == 'filename') { 670 continue; 671 } 672 $form->add_setting($setting, $task); 673 } 674 // Then add all dependencies. 675 foreach ($settings as &$setting) { 676 if ($setting->get_name() == 'filename') { 677 continue; 678 } 679 $form->add_dependencies($setting); 680 } 681 } 682 } 683 $this->stageform = $form; 684 } 685 // Return the form. 686 return $this->stageform; 687 } 688 } 689 690 /** 691 * Schema stage of backup process 692 * 693 * During the schema stage the user is required to set the settings that relate 694 * to the area that they are backing up as well as its children. 695 * 696 * @package core_backup 697 * @copyright 2010 Sam Hemelryk 698 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 699 */ 700 class restore_ui_stage_schema extends restore_ui_stage { 701 /** 702 * @var int Maximum number of settings to add to form at once 703 */ 704 const MAX_SETTINGS_BATCH = 1000; 705 706 /** 707 * Schema stage constructor 708 * @param restore_ui $ui 709 * @param array $params 710 */ 711 public function __construct(restore_ui $ui, array $params = null) { 712 $this->stage = restore_ui::STAGE_SCHEMA; 713 parent::__construct($ui, $params); 714 } 715 716 /** 717 * Processes the schema stage 718 * 719 * @param base_moodleform $form 720 * @return int The number of changes the user made 721 */ 722 public function process(base_moodleform $form = null) { 723 $form = $this->initialise_stage_form(); 724 // Check it wasn't cancelled. 725 if ($form->is_cancelled()) { 726 $this->ui->cancel_process(); 727 } 728 729 // Check it has been submit. 730 $data = $form->get_data(); 731 if ($data && confirm_sesskey()) { 732 // Get the tasks into a var so we can iterate by reference. 733 $tasks = $this->ui->get_tasks(); 734 $changes = 0; 735 // Iterate all tasks by reference. 736 foreach ($tasks as &$task) { 737 // We are only interested in schema settings. 738 if (!($task instanceof restore_root_task)) { 739 // Store as a variable so we can iterate by reference. 740 $settings = $task->get_settings(); 741 // Iterate by reference. 742 foreach ($settings as &$setting) { 743 $name = $setting->get_ui_name(); 744 if (isset($data->$name) && $data->$name != $setting->get_value()) { 745 $setting->set_value($data->$name); 746 $changes++; 747 } else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) { 748 $setting->set_value(0); 749 $changes++; 750 } 751 } 752 } 753 } 754 // Return the number of changes the user made. 755 return $changes; 756 } else { 757 return false; 758 } 759 } 760 761 /** 762 * Creates the backup_schema_form instance for this stage 763 * 764 * @return backup_schema_form 765 */ 766 protected function initialise_stage_form() { 767 global $PAGE; 768 if ($this->stageform === null) { 769 $form = new restore_schema_form($this, $PAGE->url); 770 $tasks = $this->ui->get_tasks(); 771 $courseheading = false; 772 773 // Track progress through each stage. 774 $progress = $this->ui->get_progress_reporter(); 775 $progress->start_progress('Initialise schema stage form', 3); 776 777 $progress->start_progress('', count($tasks)); 778 $done = 1; 779 $allsettings = array(); 780 foreach ($tasks as $task) { 781 if (!($task instanceof restore_root_task)) { 782 if (!$courseheading) { 783 // If we haven't already display a course heading to group nicely. 784 $form->add_heading('coursesettings', get_string('coursesettings', 'backup')); 785 $courseheading = true; 786 } 787 // Put each setting into an array of settings to add. Adding 788 // a setting individually is a very slow operation, so we add. 789 // them all in a batch later on. 790 foreach ($task->get_settings() as $setting) { 791 $allsettings[] = array($setting, $task); 792 } 793 } else if ($this->ui->enforce_changed_dependencies()) { 794 // Only show these settings if dependencies changed them. 795 // Add a root settings heading to group nicely. 796 $form->add_heading('rootsettings', get_string('rootsettings', 'backup')); 797 // Iterate all settings and add them to the form as a fixed 798 // setting. We only want schema settings to be editable. 799 foreach ($task->get_settings() as $setting) { 800 if ($setting->get_name() != 'filename') { 801 $form->add_fixed_setting($setting, $task); 802 } 803 } 804 } 805 // Update progress. 806 $progress->progress($done++); 807 } 808 $progress->end_progress(); 809 810 // Add settings for tasks in batches of up to 1000. Adding settings 811 // in larger batches improves performance, but if it takes too long, 812 // we won't be able to update the progress bar so the backup might. 813 // time out. 1000 is chosen to balance this. 814 $numsettings = count($allsettings); 815 $progress->start_progress('', ceil($numsettings / self::MAX_SETTINGS_BATCH)); 816 $start = 0; 817 $done = 1; 818 while ($start < $numsettings) { 819 $length = min(self::MAX_SETTINGS_BATCH, $numsettings - $start); 820 $form->add_settings(array_slice($allsettings, $start, $length)); 821 $start += $length; 822 $progress->progress($done++); 823 } 824 $progress->end_progress(); 825 826 // Add the dependencies for all the settings. 827 $progress->start_progress('', count($allsettings)); 828 $done = 1; 829 foreach ($allsettings as $settingtask) { 830 $form->add_dependencies($settingtask[0]); 831 $progress->progress($done++); 832 } 833 $progress->end_progress(); 834 835 $progress->end_progress(); 836 $this->stageform = $form; 837 } 838 return $this->stageform; 839 } 840 } 841 842 /** 843 * Confirmation stage 844 * 845 * On this stage the user reviews the setting for the backup and can change the filename 846 * of the file that will be generated. 847 * 848 * @package core_backup 849 * @copyright 2010 Sam Hemelryk 850 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 851 */ 852 class restore_ui_stage_review extends restore_ui_stage { 853 854 /** 855 * Constructs the stage 856 * @param restore_ui $ui 857 * @param array $params 858 */ 859 public function __construct($ui, array $params = null) { 860 $this->stage = restore_ui::STAGE_REVIEW; 861 parent::__construct($ui, $params); 862 } 863 864 /** 865 * Processes the confirmation stage 866 * 867 * @param base_moodleform $form 868 * @return int The number of changes the user made 869 */ 870 public function process(base_moodleform $form = null) { 871 $form = $this->initialise_stage_form(); 872 // Check it hasn't been cancelled. 873 if ($form->is_cancelled()) { 874 $this->ui->cancel_process(); 875 } 876 877 $data = $form->get_data(); 878 if ($data && confirm_sesskey()) { 879 return 0; 880 } else { 881 return false; 882 } 883 } 884 /** 885 * Creates the backup_confirmation_form instance this stage requires 886 * 887 * @return backup_confirmation_form 888 */ 889 protected function initialise_stage_form() { 890 global $PAGE; 891 if ($this->stageform === null) { 892 // Get the form. 893 $form = new restore_review_form($this, $PAGE->url); 894 $content = ''; 895 $courseheading = false; 896 897 $progress = $this->ui->get_progress_reporter(); 898 $tasks = $this->ui->get_tasks(); 899 $progress->start_progress('initialise_stage_form', count($tasks)); 900 $done = 1; 901 foreach ($tasks as $task) { 902 if ($task instanceof restore_root_task) { 903 // If its a backup root add a root settings heading to group nicely. 904 $form->add_heading('rootsettings', get_string('restorerootsettings', 'backup')); 905 } else if (!$courseheading) { 906 // We haven't already add a course heading. 907 $form->add_heading('coursesettings', get_string('coursesettings', 'backup')); 908 $courseheading = true; 909 } 910 // Iterate all settings, doesnt need to happen by reference. 911 foreach ($task->get_settings() as $setting) { 912 $form->add_fixed_setting($setting, $task); 913 } 914 // Update progress. 915 $progress->progress($done++); 916 } 917 $progress->end_progress(); 918 $this->stageform = $form; 919 } 920 return $this->stageform; 921 } 922 } 923 924 /** 925 * Final stage of backup 926 * 927 * This stage is special in that it is does not make use of a form. The reason for 928 * this is the order of procession of backup at this stage. 929 * The processesion is: 930 * 1. The final stage will be intialise. 931 * 2. The confirmation stage will be processed. 932 * 3. The backup will be executed 933 * 4. The complete stage will be loaded by execution 934 * 5. The complete stage will be displayed 935 * 936 * This highlights that we neither need a form nor a display method for this stage 937 * we simply need to process. 938 * 939 * @package core_backup 940 * @copyright 2010 Sam Hemelryk 941 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 942 */ 943 class restore_ui_stage_process extends restore_ui_stage { 944 945 /** 946 * There is no substage required. 947 */ 948 const SUBSTAGE_NONE = 0; 949 950 /** 951 * The prechecks substage is required/the current substage. 952 */ 953 const SUBSTAGE_PRECHECKS = 2; 954 955 /** 956 * The current substage. 957 * @var int 958 */ 959 protected $substage = 0; 960 961 /** 962 * Constructs the final stage 963 * @param base_ui $ui 964 * @param array $params 965 */ 966 public function __construct(base_ui $ui, array $params = null) { 967 $this->stage = restore_ui::STAGE_PROCESS; 968 parent::__construct($ui, $params); 969 } 970 /** 971 * Processes the final stage. 972 * 973 * In this case it checks to see if there is a sub stage that we need to display 974 * before execution, if there is we gear up to display the subpage, otherwise 975 * we return true which will lead to execution of the restore and the loading 976 * of the completed stage. 977 * 978 * @param base_moodleform $form 979 */ 980 public function process(base_moodleform $form = null) { 981 if (optional_param('cancel', false, PARAM_BOOL)) { 982 redirect(new moodle_url('/course/view.php', array('id' => $this->get_ui()->get_controller()->get_courseid()))); 983 } 984 985 // First decide whether a substage is needed. 986 $rc = $this->ui->get_controller(); 987 if ($rc->get_status() == backup::STATUS_SETTING_UI) { 988 $rc->finish_ui(); 989 } 990 if ($rc->get_status() == backup::STATUS_NEED_PRECHECK) { 991 if (!$rc->precheck_executed()) { 992 $rc->execute_precheck(true); 993 } 994 $results = $rc->get_precheck_results(); 995 if (!empty($results)) { 996 $this->substage = self::SUBSTAGE_PRECHECKS; 997 } 998 } 999 1000 $substage = optional_param('substage', null, PARAM_INT); 1001 if (empty($this->substage) && !empty($substage)) { 1002 $this->substage = $substage; 1003 // Now check whether that substage has already been submit. 1004 if ($this->substage == self::SUBSTAGE_PRECHECKS && optional_param('sesskey', null, PARAM_RAW) == sesskey()) { 1005 $info = $rc->get_info(); 1006 if (!empty($info->role_mappings->mappings)) { 1007 foreach ($info->role_mappings->mappings as $key => &$mapping) { 1008 $mapping->targetroleid = optional_param('mapping'.$key, $mapping->targetroleid, PARAM_INT); 1009 } 1010 $info->role_mappings->modified = true; 1011 } 1012 // We've processed the substage now setting it back to none so we 1013 // can move to the next stage. 1014 $this->substage = self::SUBSTAGE_NONE; 1015 } 1016 } 1017 1018 return empty($this->substage); 1019 } 1020 /** 1021 * should NEVER be called... throws an exception 1022 */ 1023 protected function initialise_stage_form() { 1024 throw new backup_ui_exception('backup_ui_must_execute_first'); 1025 } 1026 1027 /** 1028 * Renders the process stage screen 1029 * 1030 * @throws restore_ui_exception 1031 * @param core_backup_renderer $renderer renderer instance to use 1032 * @return string HTML code 1033 */ 1034 public function display(core_backup_renderer $renderer) { 1035 global $PAGE; 1036 1037 $html = ''; 1038 $haserrors = false; 1039 $url = new moodle_url($PAGE->url, array( 1040 'restore' => $this->get_uniqueid(), 1041 'stage' => restore_ui::STAGE_PROCESS, 1042 'substage' => $this->substage, 1043 'sesskey' => sesskey())); 1044 $html .= html_writer::start_tag('form', array( 1045 'action' => $url->out_omit_querystring(), 1046 'class' => 'backup-restore', 1047 'enctype' => 'application/x-www-form-urlencoded', // Enforce compatibility with our max_input_vars hack. 1048 'method' => 'post')); 1049 foreach ($url->params() as $name => $value) { 1050 $html .= html_writer::empty_tag('input', array( 1051 'type' => 'hidden', 1052 'name' => $name, 1053 'value' => $value)); 1054 } 1055 switch ($this->substage) { 1056 case self::SUBSTAGE_PRECHECKS : 1057 $results = $this->ui->get_controller()->get_precheck_results(); 1058 $info = $this->ui->get_controller()->get_info(); 1059 $haserrors = (!empty($results['errors'])); 1060 $html .= $renderer->precheck_notices($results); 1061 if (!empty($info->role_mappings->mappings)) { 1062 $context = context_course::instance($this->ui->get_controller()->get_courseid()); 1063 $assignableroles = get_assignable_roles($context, ROLENAME_ALIAS, false); 1064 1065 // Get current role mappings. 1066 $currentroles = role_fix_names(get_all_roles(), $context); 1067 // Get backup role mappings. 1068 $rolemappings = $info->role_mappings->mappings; 1069 1070 array_map(function($rolemapping) use ($currentroles) { 1071 foreach ($currentroles as $role) { 1072 // Find matching archetype to determine the backup's shortname for label display. 1073 if ($rolemapping->archetype == $role->archetype) { 1074 $rolemapping->name = $rolemapping->shortname; 1075 break; 1076 } 1077 } 1078 if ($rolemapping->name == null) { 1079 $rolemapping->name = get_string('undefinedrolemapping', 'backup', $rolemapping->archetype); 1080 } 1081 }, $rolemappings); 1082 1083 $html .= $renderer->role_mappings($rolemappings, $assignableroles); 1084 } 1085 break; 1086 default: 1087 throw new restore_ui_exception('backup_ui_must_execute_first'); 1088 } 1089 $html .= $renderer->substage_buttons($haserrors); 1090 $html .= html_writer::end_tag('form'); 1091 1092 return $html; 1093 } 1094 1095 /** 1096 * Returns true if this stage can have sub-stages. 1097 * @return bool|false 1098 */ 1099 public function has_sub_stages() { 1100 return true; 1101 } 1102 } 1103 1104 /** 1105 * This is the completed stage. 1106 * 1107 * Once this is displayed there is nothing more to do. 1108 * 1109 * @package core_backup 1110 * @copyright 2010 Sam Hemelryk 1111 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1112 */ 1113 class restore_ui_stage_complete extends restore_ui_stage_process { 1114 1115 /** 1116 * The results of the backup execution 1117 * @var array 1118 */ 1119 protected $results; 1120 1121 /** 1122 * Constructs the complete backup stage 1123 * @param restore_ui $ui 1124 * @param array $params 1125 * @param array $results 1126 */ 1127 public function __construct(restore_ui $ui, array $params = null, array $results = null) { 1128 $this->results = $results; 1129 parent::__construct($ui, $params); 1130 $this->stage = restore_ui::STAGE_COMPLETE; 1131 } 1132 1133 /** 1134 * Displays the completed backup stage. 1135 * 1136 * Currently this just envolves redirecting to the file browser with an 1137 * appropriate message. 1138 * 1139 * @param core_backup_renderer $renderer 1140 * @return string HTML code to echo 1141 */ 1142 public function display(core_backup_renderer $renderer) { 1143 1144 $html = ''; 1145 if (!empty($this->results['file_aliases_restore_failures'])) { 1146 $html .= $renderer->box_start('generalbox filealiasesfailures'); 1147 $html .= $renderer->heading_with_help(get_string('filealiasesrestorefailures', 'core_backup'), 1148 'filealiasesrestorefailures', 'core_backup'); 1149 $html .= $renderer->container(get_string('filealiasesrestorefailuresinfo', 'core_backup')); 1150 $html .= $renderer->container_start('aliaseslist'); 1151 $html .= html_writer::start_tag('ul'); 1152 foreach ($this->results['file_aliases_restore_failures'] as $alias) { 1153 $html .= html_writer::tag('li', s($alias)); 1154 } 1155 $html .= html_writer::end_tag('ul'); 1156 $html .= $renderer->container_end(); 1157 $html .= $renderer->box_end(); 1158 } 1159 $html .= $renderer->box_start(); 1160 if (array_key_exists('file_missing_in_backup', $this->results)) { 1161 $html .= $renderer->notification(get_string('restorefileweremissing', 'backup'), 'notifyproblem'); 1162 } 1163 $html .= $renderer->notification(get_string('restoreexecutionsuccess', 'backup'), 'notifysuccess'); 1164 1165 $courseurl = course_get_url($this->get_ui()->get_controller()->get_courseid()); 1166 $html .= $renderer->continue_button($courseurl, 'get'); 1167 1168 $html .= $renderer->box_end(); 1169 1170 return $html; 1171 } 1172 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body