Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
   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   * This file contains the backup user interface class
  19   *
  20   * @package   core_backup
  21   * @copyright 2010 Sam Hemelryk
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  /**
  26   * This is the backup user interface class
  27   *
  28   * The backup user interface class manages the user interface and backup for
  29   * Moodle.
  30   *
  31   * @package   core_backup
  32   * @copyright 2010 Sam Hemelryk
  33   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  abstract class base_ui {
  36      /**
  37       * The progress of this instance of the backup ui class
  38       * It is in the initial stage.
  39       */
  40      const PROGRESS_INTIAL = 0;
  41  
  42      /**
  43       * The progress of this instance of the backup ui class
  44       * It is processed.
  45       */
  46      const PROGRESS_PROCESSED = 1;
  47  
  48      /**
  49       * The progress of this instance of the backup ui class
  50       * It is saved.
  51       */
  52      const PROGRESS_SAVED = 2;
  53  
  54      /**
  55       * The progress of this instance of the backup ui class
  56       * It has been executed.
  57       */
  58      const PROGRESS_EXECUTED = 3;
  59  
  60      /**
  61       * The controller
  62       * @var backup_controller|restore_controller
  63       */
  64      protected $controller;
  65  
  66      /**
  67       * The current stage
  68       * @var base_ui_stage
  69       */
  70      protected $stage;
  71  
  72      /**
  73       * The current progress of the UI
  74       * @var int One of self::PROGRESS_*
  75       */
  76      protected $progress;
  77  
  78      /**
  79       * The number of changes made by dependency enforcement
  80       * @var int
  81       */
  82      protected $dependencychanges = 0;
  83  
  84      /**
  85       * Yay for constructors
  86       * @param backup_controller $controller
  87       * @param array $params
  88       */
  89      public function __construct($controller, array $params = null) {
  90          $this->controller = $controller;
  91          $this->progress = self::PROGRESS_INTIAL;
  92          $this->stage = $this->initialise_stage(null, $params);
  93          if ($this->controller) {
  94              // Process UI event before to be safe.
  95              $this->controller->process_ui_event();
  96          }
  97      }
  98  
  99      /**
 100       * Destorys the backup controller and the loaded stage.
 101       */
 102      public function destroy() {
 103  
 104          if ($this->controller) {
 105              $this->controller->destroy();
 106          }
 107          unset($this->stage);
 108  
 109      }
 110  
 111      /**
 112       * Intialises what ever stage is requested. If none are requested we check
 113       * params for 'stage' and default to initial
 114       *
 115       * @param int|null $stage The desired stage to intialise or null for the default
 116       * @param array $params
 117       * @return base_ui_stage
 118       */
 119      abstract protected function initialise_stage($stage = null, array $params = null);
 120  
 121      /**
 122       * This processes the current stage of the backup
 123       * @throws backup_ui_exception
 124       * @return bool
 125       */
 126      public function process() {
 127          if ($this->progress >= self::PROGRESS_PROCESSED) {
 128              throw new backup_ui_exception('backupuialreadyprocessed');
 129          }
 130          $this->progress = self::PROGRESS_PROCESSED;
 131  
 132          if (optional_param('previous', false, PARAM_BOOL) && $this->stage->get_stage() > $this->get_first_stage_id()) {
 133              $this->stage = $this->initialise_stage($this->stage->get_prev_stage(), $this->stage->get_params());
 134              return false;
 135          }
 136  
 137          // Process the stage.
 138          $processoutcome = $this->stage->process();
 139  
 140          if ($processoutcome !== false) {
 141              $this->stage = $this->initialise_stage($this->stage->get_next_stage(), $this->stage->get_params());
 142          }
 143  
 144          // Process UI event after to check changes are valid.
 145          $this->controller->process_ui_event();
 146          return $processoutcome;
 147      }
 148  
 149      /**
 150       * Saves the backup controller.
 151       *
 152       * Once this has been called nothing else can be changed in the controller.
 153       *
 154       * @throws base_ui_exception
 155       * @return bool
 156       */
 157      public function save_controller() {
 158          if ($this->progress >= self::PROGRESS_SAVED) {
 159              throw new base_ui_exception('backupuialreadysaved');
 160          }
 161          $this->progress = self::PROGRESS_SAVED;
 162          // First enforce dependencies.
 163          $this->enforce_dependencies();
 164          // Process UI event after to check any changes are valid.
 165          $this->controller->process_ui_event();
 166          // Save the controller.
 167          $this->controller->save_controller();
 168          return true;
 169      }
 170  
 171      /**
 172       * Displays the UI for the backup!
 173       *
 174       * @throws base_ui_exception
 175       * @param core_backup_renderer $renderer
 176       * @return string HTML code to echo
 177       */
 178      public function display(core_backup_renderer $renderer) {
 179          if ($this->progress < self::PROGRESS_SAVED) {
 180              throw new base_ui_exception('backupsavebeforedisplay');
 181          }
 182          return $this->stage->display($renderer);
 183      }
 184  
 185      /**
 186       * Gets all backup tasks from the controller
 187       * @return array Array of backup_task
 188       */
 189      public function get_tasks() {
 190          $plan = $this->controller->get_plan();
 191          $tasks = $plan->get_tasks();
 192          return $tasks;
 193      }
 194  
 195      /**
 196       * Gets the stage we are on
 197       * @return int
 198       */
 199      public function get_stage() {
 200          return $this->stage->get_stage();
 201      }
 202  
 203      /**
 204       * Gets the name of the stage we are on
 205       * @return string
 206       */
 207      public function get_stage_name() {
 208          return $this->stage->get_name();
 209      }
 210  
 211      /**
 212       * Gets the backup id from the controller
 213       * @return string
 214       */
 215      abstract public function get_uniqueid();
 216  
 217      /**
 218       * Executes the backup plan
 219       * @return bool
 220       */
 221      abstract public function execute();
 222  
 223      /**
 224       * Enforces dependencies on all settings. Call before save
 225       * @return bool True if dependencies were enforced and changes were made
 226       */
 227      protected function enforce_dependencies() {
 228          // Get the plan.
 229          $plan = $this->controller->get_plan();
 230          // Get the tasks as a var so we can iterate by reference.
 231          $tasks = $plan->get_tasks();
 232          $changes = 0;
 233          foreach ($tasks as &$task) {
 234              // Store as a var so we can iterate by reference.
 235              $settings = $task->get_settings();
 236              foreach ($settings as &$setting) {
 237                  // Get all dependencies for iteration by reference.
 238                  $dependencies = $setting->get_dependencies();
 239                  foreach ($dependencies as &$dependency) {
 240                      // Enforce each dependency.
 241                      if ($dependency->enforce()) {
 242                          $changes++;
 243                      }
 244                  }
 245              }
 246          }
 247          // Store the number of settings that changed through enforcement.
 248          $this->dependencychanges = $changes;
 249          return ($changes > 0);
 250      }
 251  
 252      /**
 253       * Returns true if enforce_dependencies changed any settings
 254       * @return bool
 255       */
 256      public function enforce_changed_dependencies() {
 257          return ($this->dependencychanges > 0);
 258      }
 259  
 260      /**
 261       * Loads the backup controller if we are tracking one
 262       * @throws coding_exception
 263       * @param string|bool $uniqueid
 264       * @return backup_controller|false
 265       */
 266      public static function load_controller($uniqueid = false) {
 267          throw new coding_exception('load_controller() method needs to be overridden in each subclass of base_ui');
 268      }
 269  
 270      /**
 271       * Cancels the current backup/restore and redirects the user back to the relevant place
 272       */
 273      public function cancel_process() {
 274          global $PAGE;
 275          // Determine the appropriate URL to redirect the user to.
 276          if ($PAGE->context->contextlevel == CONTEXT_MODULE && $PAGE->cm !== null) {
 277              $relevanturl = new moodle_url('/mod/'.$PAGE->cm->modname.'/view.php', array('id' => $PAGE->cm->id));
 278          } else {
 279              $relevanturl = new moodle_url('/course/view.php', array('id' => $PAGE->course->id));
 280          }
 281          redirect($relevanturl);
 282      }
 283  
 284      /**
 285       * Gets an array of progress bar items that can be displayed through the backup renderer.
 286       * @return array Array of items for the progress bar
 287       */
 288      abstract public function get_progress_bar();
 289      /**
 290       * Gets the format for the backup
 291       * @return int
 292       */
 293      public function get_format() {
 294          return $this->controller->get_format();
 295      }
 296      /**
 297       * Gets the type of the backup
 298       * @return int
 299       */
 300      public function get_type() {
 301          return $this->controller->get_type();
 302      }
 303  
 304      /**
 305       * Returns the controller object.
 306       * @return backup_controller|restore_controller
 307       */
 308      public function get_controller() {
 309          return $this->controller;
 310      }
 311      /**
 312       * Gets the ID used in creating the controller. Relates to course/section/cm
 313       * @return int
 314       */
 315      public function get_controller_id() {
 316          return $this->controller->get_id();
 317      }
 318      /**
 319       * Gets the requested setting
 320       * @param string $name
 321       * @param bool $default
 322       * @return base_setting
 323       */
 324      public function get_setting($name, $default = false) {
 325          try {
 326              return $this->controller->get_plan()->get_setting($name);
 327          } catch (Exception $e) {
 328              debugging('Failed to find the setting: '.$name, DEBUG_DEVELOPER);
 329              return $default;
 330          }
 331      }
 332      /**
 333       * Gets the value for the requested setting
 334       *
 335       * @param string $name
 336       * @param bool $default
 337       * @return mixed
 338       */
 339      public function get_setting_value($name, $default = false) {
 340          try {
 341              return $this->controller->get_plan()->get_setting($name)->get_value();
 342          } catch (Exception $e) {
 343              debugging('Failed to find the setting: '.$name, DEBUG_DEVELOPER);
 344              return $default;
 345          }
 346      }
 347  
 348      /**
 349       * Returns the name of this stage.
 350       * @return mixed
 351       */
 352      abstract public function get_name();
 353  
 354      /**
 355       * Returns the first stage ID.
 356       * @return mixed
 357       */
 358      abstract public function get_first_stage_id();
 359  }
 360  
 361  /**
 362   * Backup user interface exception. Modelled off the backup_exception class
 363   *
 364   * @package   core_backup
 365   * @copyright 2010 Sam Hemelryk
 366   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 367   */
 368  class base_ui_exception extends backup_exception {}