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.

Differences Between: [Versions 401 and 402] [Versions 401 and 403]

   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   * Defines restore_plugin class
  20   *
  21   * @package     core_backup
  22   * @subpackage  moodle2
  23   * @category    backup
  24   * @copyright   2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  25   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  26   */
  27  
  28  defined('MOODLE_INTERNAL') || die();
  29  
  30  /**
  31   * Class implementing the plugins support for moodle2 restore
  32   *
  33   * TODO: Finish phpdocs
  34   */
  35  abstract class restore_plugin {
  36  
  37      /** @var string */
  38      protected $plugintype;
  39      /** @var string */
  40      protected $pluginname;
  41      /** @var string */
  42      protected $connectionpoint;
  43      /** @var restore_structure_step */
  44      protected $step;
  45      /** @var restore_course_task|restore_activity_task */
  46      protected $task;
  47  
  48      /**
  49       * restore_plugin constructor.
  50       *
  51       * @param string $plugintype
  52       * @param string $pluginname
  53       * @param restore_structure_step $step
  54       */
  55      public function __construct($plugintype, $pluginname, $step) {
  56          $this->plugintype = $plugintype;
  57          $this->pluginname = $pluginname;
  58          $this->step          = $step;
  59          $this->task          = $step->get_task();
  60          $this->connectionpoint = '';
  61      }
  62  
  63      public function define_plugin_structure($connectionpoint) {
  64          if (!$connectionpoint instanceof restore_path_element) {
  65              throw new restore_step_exception('restore_path_element_required', $connectionpoint);
  66          }
  67  
  68          $paths = array();
  69          $this->connectionpoint = $connectionpoint;
  70          $methodname = 'define_' . basename($this->connectionpoint->get_path()) . '_plugin_structure';
  71  
  72          if (method_exists($this, $methodname)) {
  73              if ($pluginpaths = $this->$methodname()) {
  74                  foreach ($pluginpaths as $path) {
  75                      if ($path->get_processing_object() === null && !$this->step->grouped_parent_exists($path, $paths)) {
  76                          $path->set_processing_object($this);
  77                      }
  78                      $paths[] = $path;
  79                  }
  80              }
  81          }
  82          return $paths;
  83      }
  84  
  85      /**
  86       * after_execute dispatcher for any restore_plugin class
  87       *
  88       * This method will dispatch execution to the corresponding
  89       * after_execute_xxx() method when available, with xxx
  90       * being the connection point of the instance, so plugin
  91       * classes with multiple connection points will support
  92       * multiple after_execute methods, one for each connection point
  93       */
  94      public function launch_after_execute_methods() {
  95          // Check if the after_execute method exists and launch it
  96          $afterexecute = 'after_execute_' . basename($this->connectionpoint->get_path());
  97          if (method_exists($this, $afterexecute)) {
  98              $this->$afterexecute();
  99          }
 100      }
 101  
 102      /**
 103       * after_restore dispatcher for any restore_plugin class
 104       *
 105       * This method will dispatch execution to the corresponding
 106       * after_restore_xxx() method when available, with xxx
 107       * being the connection point of the instance, so plugin
 108       * classes with multiple connection points will support
 109       * multiple after_restore methods, one for each connection point
 110       */
 111      public function launch_after_restore_methods() {
 112          // Check if the after_restore method exists and launch it
 113          $afterrestore = 'after_restore_' . basename($this->connectionpoint->get_path());
 114          if (method_exists($this, $afterrestore)) {
 115              $this->$afterrestore();
 116          }
 117      }
 118  
 119      /**
 120       * Returns one array with all the decode contents
 121       * to be processed by the links decoder
 122       *
 123       * This method, given one plugin type, returns one
 124       * array of {@link restore_decode_content} objects
 125       * that will be added to the restore decoder in order
 126       * to perform modifications under the plugin contents.
 127       *
 128       * The objects are retrieved by calling to the {@link define_decode_contents}
 129       * method (when available), first in the main restore_xxxx_plugin class
 130       * and later on each of the available subclasses
 131       */
 132      static public function get_restore_decode_contents($plugintype) {
 133          $decodecontents = array();
 134          // Check the requested plugintype is a valid one
 135          if (!array_key_exists($plugintype, core_component::get_plugin_types($plugintype))) {
 136               throw new backup_step_exception('incorrect_plugin_type', $plugintype);
 137          }
 138          // Check the base plugin class exists
 139          $classname = 'restore_' . $plugintype . '_plugin';
 140          if (!class_exists($classname)) {
 141               throw new backup_step_exception('plugin_class_not_found', $classname);
 142          }
 143          // First, call to the define_plugin_decode_contents in the base plugin class
 144          // (must exist by design in all the plugin base classes)
 145          if (method_exists($classname, 'define_plugin_decode_contents')) {
 146              $decodecontents = array_merge($decodecontents, call_user_func(array($classname, 'define_plugin_decode_contents')));
 147          }
 148          // Now, iterate over all the possible plugins available
 149          // (only the needed ones have been loaded, so they will
 150          // be the ones being asked here). Fetch their restore contents
 151          // by calling (if exists) to their define_decode_contents() method
 152          $plugins = core_component::get_plugin_list($plugintype);
 153          foreach ($plugins as $plugin => $plugindir) {
 154              $classname = 'restore_' . $plugintype . '_' . $plugin . '_plugin';
 155              if (class_exists($classname)) {
 156                  if (method_exists($classname, 'define_decode_contents')) {
 157                      $decodecontents = array_merge($decodecontents, call_user_func(array($classname, 'define_decode_contents')));
 158                  }
 159              }
 160          }
 161          return $decodecontents;
 162      }
 163  
 164      /**
 165       * Define the contents in the plugin that must be
 166       * processed by the link decoder
 167       */
 168      static public function define_plugin_decode_contents() {
 169          throw new coding_exception('define_plugin_decode_contents() method needs to be overridden in each subclass of restore_plugin');
 170      }
 171  
 172  // Protected API starts here
 173  
 174  // restore_step/structure_step/task wrappers
 175  
 176      protected function get_restoreid() {
 177          if (is_null($this->task)) {
 178              throw new restore_step_exception('not_specified_restore_task');
 179          }
 180          return $this->task->get_restoreid();
 181      }
 182  
 183      /**
 184       * To send ids pairs to backup_ids_table and to store them into paths
 185       *
 186       * This method will send the given itemname and old/new ids to the
 187       * backup_ids_temp table, and, at the same time, will save the new id
 188       * into the corresponding restore_path_element for easier access
 189       * by children. Also will inject the known old context id for the task
 190       * in case it's going to be used for restoring files later
 191       */
 192      protected function set_mapping($itemname, $oldid, $newid, $restorefiles = false, $filesctxid = null, $parentid = null) {
 193          $this->step->set_mapping($itemname, $oldid, $newid, $restorefiles, $filesctxid, $parentid);
 194      }
 195  
 196      /**
 197       * Returns the latest (parent) old id mapped by one pathelement
 198       */
 199      protected function get_old_parentid($itemname) {
 200          return $this->step->get_old_parentid($itemname);
 201      }
 202  
 203      /**
 204       * Returns the latest (parent) new id mapped by one pathelement
 205       */
 206      protected function get_new_parentid($itemname) {
 207          return $this->step->get_new_parentid($itemname);
 208      }
 209  
 210      /**
 211       * Return the new id of a mapping for the given itemname
 212       *
 213       * @param string $itemname the type of item
 214       * @param int $oldid the item ID from the backup
 215       * @param mixed $ifnotfound what to return if $oldid wasnt found. Defaults to false
 216       */
 217      protected function get_mappingid($itemname, $oldid, $ifnotfound = false) {
 218          return $this->step->get_mappingid($itemname, $oldid, $ifnotfound);
 219      }
 220  
 221      /**
 222       * Return the complete mapping from the given itemname, itemid
 223       */
 224      protected function get_mapping($itemname, $oldid) {
 225          return $this->step->get_mapping($itemname, $oldid);
 226      }
 227  
 228      /**
 229       * Add all the existing file, given their component and filearea and one backup_ids itemname to match with
 230       */
 231      protected function add_related_files($component, $filearea, $mappingitemname, $filesctxid = null, $olditemid = null) {
 232          $this->step->add_related_files($component, $filearea, $mappingitemname, $filesctxid, $olditemid);
 233      }
 234  
 235      /**
 236       * Apply course startdate offset based in original course startdate and course_offset_startdate setting
 237       * Note we are using one static cache here, but *by restoreid*, so it's ok for concurrence/multiple
 238       * executions in the same request
 239       */
 240      protected function apply_date_offset($value) {
 241          return $this->step->apply_date_offset($value);
 242      }
 243  
 244      /**
 245       * Returns the value of one (task/plan) setting
 246       */
 247      protected function get_setting_value($name) {
 248          if (is_null($this->task)) {
 249              throw new restore_step_exception('not_specified_restore_task');
 250          }
 251          return $this->task->get_setting_value($name);
 252      }
 253  
 254  // end of restore_step/structure_step/task wrappers
 255  
 256      /**
 257       * Simple helper function that returns the name for the restore_path_element
 258       * It's not mandatory to use it but recommended ;-)
 259       */
 260      protected function get_namefor($name = '') {
 261          $name = $name !== '' ? '_' . $name : '';
 262          return $this->plugintype . '_' . $this->pluginname . $name;
 263      }
 264  
 265      /**
 266       * Simple helper function that returns the base (prefix) of the path for the restore_path_element
 267       * Useful if we used get_recommended_name() in backup. It's not mandatory to use it but recommended ;-)
 268       */
 269      protected function get_pathfor($path = '') {
 270          $path = trim($path, '/') !== '' ? '/' . trim($path, '/') : '';
 271          return $this->connectionpoint->get_path() . '/' .
 272                 'plugin_' . $this->plugintype . '_' .
 273                 $this->pluginname . '_' . basename($this->connectionpoint->get_path()) . $path;
 274      }
 275  
 276      /**
 277       * Get the task we are part of.
 278       *
 279       * @return restore_activity_task|restore_course_task the task.
 280       */
 281      protected function get_task() {
 282          return $this->task;
 283      }
 284  }