Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  
   3  // This file is part of Moodle - http://moodle.org/
   4  //
   5  // Moodle is free software: you can redistribute it and/or modify
   6  // it under the terms of the GNU General Public License as published by
   7  // the Free Software Foundation, either version 3 of the License, or
   8  // (at your option) any later version.
   9  //
  10  // Moodle is distributed in the hope that it will be useful,
  11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13  // GNU General Public License for more details.
  14  //
  15  // You should have received a copy of the GNU General Public License
  16  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  17  
  18  /**
  19   * @package moodlecore
  20   * @subpackage backup-plan
  21   * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  /**
  26   * Abstract class defining the basis for one execution (backup/restore) plan
  27   *
  28   * TODO: Finish phpdocs
  29   */
  30  abstract class base_plan implements checksumable, executable {
  31  
  32      protected $name;      // One simple name for identification purposes
  33      protected $settings;  // One array of (accumulated from tasks) base_setting elements
  34      protected $tasks;     // One array of base_task elements
  35      protected $results;   // One array of results received from tasks
  36  
  37      protected $built;     // Flag to know if one plan has been built
  38  
  39      /**
  40       * Constructor - instantiates one object of this class
  41       */
  42      public function __construct($name) {
  43          $this->name = $name;
  44          $this->settings = array();
  45          $this->tasks    = array();
  46          $this->results  = array();
  47          $this->built = false;
  48      }
  49  
  50      public function get_name() {
  51          return $this->name;
  52      }
  53  
  54      public function add_task($task) {
  55          if (! $task instanceof base_task) {
  56              throw new base_plan_exception('wrong_base_task_specified');
  57          }
  58          $this->tasks[] = $task;
  59          // link the task with the plan
  60          $task->set_plan($this);
  61          // Append task settings to plan array, if not present, for comodity
  62          foreach ($task->get_settings() as $key => $setting) {
  63              // Check if there is already a setting for this name.
  64              $name = $setting->get_name();
  65              if (!isset($this->settings[$name])) {
  66                  // There is no setting, so add it.
  67                  $this->settings[$name] = $setting;
  68              } else if ($this->settings[$name] != $setting) {
  69                  // If the setting already exists AND it is not the same setting,
  70                  // then throw an error. (I.e. you're allowed to add the same
  71                  // setting twice, but cannot add two different ones with same
  72                  // name.)
  73                  throw new base_plan_exception('multiple_settings_by_name_found', $name);
  74              }
  75          }
  76      }
  77  
  78      public function get_tasks() {
  79          return $this->tasks;
  80      }
  81  
  82      /**
  83       * Add the passed info to the plan results
  84       *
  85       * At the moment we expect an associative array structure to be merged into
  86       * the current results. In the future, some sort of base_result class may
  87       * be introduced.
  88       *
  89       * @param array $result associative array describing a result of a task/step
  90       */
  91      public function add_result($result) {
  92          if (!is_array($result)) {
  93              throw new coding_exception('Associative array is expected as a parameter of add_result()');
  94          }
  95          $this->results = array_merge($this->results, $result);
  96      }
  97  
  98      /**
  99       * Return the results collected via {@link self::add_result()} method
 100       *
 101       * @return array
 102       */
 103      public function get_results() {
 104          return $this->results;
 105      }
 106  
 107      public function get_settings() {
 108          return $this->settings;
 109      }
 110  
 111      /**
 112       * return one setting by name, useful to request root/course settings
 113       * that are, by definition, unique by name.
 114       *
 115       * @param string $name name of the setting
 116       * @return base_setting
 117       * @throws base_plan_exception if setting name is not found.
 118       */
 119      public function get_setting($name) {
 120          $result = null;
 121          if (isset($this->settings[$name])) {
 122              $result = $this->settings[$name];
 123          } else {
 124              throw new base_plan_exception('setting_by_name_not_found', $name);
 125          }
 126          return $result;
 127      }
 128  
 129      /**
 130       * For debug only. Get a simple test display of all the settings.
 131       *
 132       * @return string
 133       */
 134      public function debug_display_all_settings_values(): string {
 135          $result = '';
 136          foreach ($this->settings as $name => $setting) {
 137              $result .= $name . ': ' . $setting->get_value() . "\n";
 138          }
 139          return $result;
 140      }
 141  
 142      /**
 143       * Wrapper over @get_setting() that returns if the requested setting exists or no
 144       */
 145      public function setting_exists($name) {
 146          try {
 147              $this->get_setting($name);
 148              return true;
 149          } catch (base_plan_exception $e) {
 150              // Nothing to do
 151          }
 152          return false;
 153      }
 154  
 155  
 156      /**
 157       * Function responsible for building the tasks of any plan
 158       * with their corresponding settings
 159       * (must set the $built property to true)
 160       */
 161      public abstract function build();
 162  
 163      public function is_checksum_correct($checksum) {
 164          return $this->calculate_checksum() === $checksum;
 165      }
 166  
 167      public function calculate_checksum() {
 168          // Let's do it using name and tasks (settings are part of tasks)
 169          return md5($this->name . '-' . backup_general_helper::array_checksum_recursive($this->tasks));
 170      }
 171  
 172      /**
 173       * Function responsible for executing the tasks of any plan
 174       */
 175      public function execute() {
 176          if (!$this->built) {
 177              throw new base_plan_exception('base_plan_not_built');
 178          }
 179  
 180          // Calculate the total weight of all tasks and start progress tracking.
 181          $progress = $this->get_progress();
 182          $totalweight = 0;
 183          foreach ($this->tasks as $task) {
 184              $totalweight += $task->get_weight();
 185          }
 186          $progress->start_progress($this->get_name(), $totalweight);
 187  
 188          // Build and execute all tasks.
 189          foreach ($this->tasks as $task) {
 190              $task->build();
 191              $task->execute();
 192          }
 193  
 194          // Finish progress tracking.
 195          $progress->end_progress();
 196      }
 197  
 198      /**
 199       * Gets the progress reporter, which can be used to report progress within
 200       * the backup or restore process.
 201       *
 202       * @return \core\progress\base Progress reporting object
 203       */
 204      public abstract function get_progress();
 205  
 206      /**
 207       * Destroy all circular references. It helps PHP 5.2 a lot!
 208       */
 209      public function destroy() {
 210          // Before reseting anything, call destroy recursively
 211          foreach ($this->tasks as $task) {
 212              $task->destroy();
 213          }
 214          foreach ($this->settings as $setting) {
 215              $setting->destroy();
 216          }
 217          // Everything has been destroyed recursively, now we can reset safely
 218          $this->tasks = array();
 219          $this->settings = array();
 220      }
 221  }
 222  
 223  
 224  /*
 225   * Exception class used by all the @base_plan stuff
 226   */
 227  class base_plan_exception extends moodle_exception {
 228  
 229      public function __construct($errorcode, $a=NULL, $debuginfo=null) {
 230          parent::__construct($errorcode, '', '', $a, $debuginfo);
 231      }
 232  }