PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/backup/util/plan/backup_structure_step.class.php

https://gitlab.com/unofficial-mirrors/moodle
PHP | 264 lines | 118 code | 37 blank | 109 comment | 15 complexity | e104639037a5d36ba0bedc9d4edef2e2 MD5 | raw file
  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. * @package moodlecore
  18. * @subpackage backup-plan
  19. * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  20. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  21. */
  22. /**
  23. * Abstract class defining the needed stuff to backup one @backup_structure
  24. *
  25. * TODO: Finish phpdocs
  26. */
  27. abstract class backup_structure_step extends backup_step {
  28. protected $filename; // Name of the file to be generated
  29. protected $contenttransformer; // xml content transformer being used
  30. // (need it here, apart from xml_writer,
  31. // thanks to serialized data to process -
  32. // say thanks to blocks!)
  33. /**
  34. * Constructor - instantiates one object of this class
  35. */
  36. public function __construct($name, $filename, $task = null) {
  37. if (!is_null($task) && !($task instanceof backup_task)) {
  38. throw new backup_step_exception('wrong_backup_task_specified');
  39. }
  40. $this->filename = $filename;
  41. $this->contenttransformer = null;
  42. parent::__construct($name, $task);
  43. }
  44. public function execute() {
  45. if (!$this->execute_condition()) { // Check any condition to execute this
  46. return;
  47. }
  48. $fullpath = $this->task->get_taskbasepath();
  49. // We MUST have one fullpath here, else, error
  50. if (empty($fullpath)) {
  51. throw new backup_step_exception('backup_structure_step_undefined_fullpath');
  52. }
  53. // Append the filename to the fullpath
  54. $fullpath = rtrim($fullpath, '/') . '/' . $this->filename;
  55. // Create output, transformer, writer, processor
  56. $xo = new file_xml_output($fullpath);
  57. $xt = null;
  58. if (class_exists('backup_xml_transformer')) {
  59. $xt = new backup_xml_transformer($this->get_courseid());
  60. $this->contenttransformer = $xt; // Save the reference to the transformer
  61. // as far as we are going to need it out
  62. // from xml_writer (blame serialized data!)
  63. }
  64. $xw = new xml_writer($xo, $xt);
  65. $progress = $this->task->get_progress();
  66. $progress->start_progress($this->get_name());
  67. $pr = new backup_structure_processor($xw, $progress);
  68. // Set processor variables from settings
  69. foreach ($this->get_settings() as $setting) {
  70. $pr->set_var($setting->get_name(), $setting->get_value());
  71. }
  72. // Add backupid as one more var for processor
  73. $pr->set_var(backup::VAR_BACKUPID, $this->get_backupid());
  74. // Get structure definition
  75. $structure = $this->define_structure();
  76. if (! $structure instanceof backup_nested_element) {
  77. throw new backup_step_exception('backup_structure_step_wrong_structure');
  78. }
  79. // Start writer
  80. $xw->start();
  81. // Process structure definition
  82. $structure->process($pr);
  83. // Get the results from the nested elements
  84. $results = $structure->get_results();
  85. // Get the log messages to append to the log
  86. $logs = $structure->get_logs();
  87. foreach ($logs as $log) {
  88. $this->log($log->message, $log->level, $log->a, $log->depth, $log->display);
  89. }
  90. // Close everything
  91. $xw->stop();
  92. $progress->end_progress();
  93. // Destroy the structure. It helps PHP 5.2 memory a lot!
  94. $structure->destroy();
  95. return $results;
  96. }
  97. /**
  98. * As far as backup structure steps are implementing backup_plugin stuff, they need to
  99. * have the parent task available for wrapping purposes (get course/context....)
  100. */
  101. public function get_task() {
  102. return $this->task;
  103. }
  104. // Protected API starts here
  105. /**
  106. * Add plugin structure to any element in the structure backup tree
  107. *
  108. * @param string $plugintype type of plugin as defined by core_component::get_plugin_types()
  109. * @param backup_nested_element $element element in the structure backup tree that
  110. * we are going to add plugin information to
  111. * @param bool $multiple to define if multiple plugins can produce information
  112. * for each instance of $element (true) or no (false)
  113. */
  114. protected function add_plugin_structure($plugintype, $element, $multiple) {
  115. global $CFG;
  116. // Check the requested plugintype is a valid one
  117. if (!array_key_exists($plugintype, core_component::get_plugin_types($plugintype))) {
  118. throw new backup_step_exception('incorrect_plugin_type', $plugintype);
  119. }
  120. // Arrived here, plugin is correct, let's create the optigroup
  121. $optigroupname = $plugintype . '_' . $element->get_name() . '_plugin';
  122. $optigroup = new backup_optigroup($optigroupname, null, $multiple);
  123. $element->add_child($optigroup); // Add optigroup to stay connected since beginning
  124. // Get all the optigroup_elements, looking across all the plugin dirs
  125. $pluginsdirs = core_component::get_plugin_list($plugintype);
  126. foreach ($pluginsdirs as $name => $plugindir) {
  127. $classname = 'backup_' . $plugintype . '_' . $name . '_plugin';
  128. $backupfile = $plugindir . '/backup/moodle2/' . $classname . '.class.php';
  129. if (file_exists($backupfile)) {
  130. require_once($backupfile);
  131. $backupplugin = new $classname($plugintype, $name, $optigroup, $this);
  132. // Add plugin returned structure to optigroup
  133. $backupplugin->define_plugin_structure($element->get_name());
  134. }
  135. }
  136. }
  137. /**
  138. * Add subplugin structure for a given plugin to any element in the structure backup tree.
  139. *
  140. * This method allows the injection of subplugins (of a specified plugin) data to any
  141. * element in any backup structure.
  142. *
  143. * NOTE: Initially subplugins were only available for activities (mod), so only the
  144. * {@link backup_activity_structure_step} class had support for them, always
  145. * looking for /mod/modulenanme subplugins. This new method is a generalization of the
  146. * existing one for activities, supporting all subplugins injecting information everywhere.
  147. *
  148. * @param string $subplugintype type of subplugin as defined in plugin's db/subplugins.php.
  149. * @param backup_nested_element $element element in the backup tree (anywhere) that
  150. * we are going to add subplugin information to.
  151. * @param bool $multiple to define if multiple subplugins can produce information
  152. * for each instance of $element (true) or no (false).
  153. * @param string $plugintype type of the plugin.
  154. * @param string $pluginname name of the plugin.
  155. * @return void
  156. */
  157. protected function add_subplugin_structure($subplugintype, $element, $multiple, $plugintype = null, $pluginname = null) {
  158. global $CFG;
  159. // This global declaration is required, because where we do require_once($backupfile);
  160. // That file may in turn try to do require_once($CFG->dirroot ...).
  161. // That worked in the past, we should keep it working.
  162. // Verify if this is a BC call for an activity backup. See NOTE above for this special case.
  163. if ($plugintype === null and $pluginname === null) {
  164. $plugintype = 'mod';
  165. $pluginname = $this->task->get_modulename();
  166. // TODO: Once all the calls have been changed to add both not null plugintype and pluginname, add a debugging here.
  167. }
  168. // Check the requested plugintype is a valid one.
  169. if (!array_key_exists($plugintype, core_component::get_plugin_types())) {
  170. throw new backup_step_exception('incorrect_plugin_type', $plugintype);
  171. }
  172. // Check the requested pluginname, for the specified plugintype, is a valid one.
  173. if (!array_key_exists($pluginname, core_component::get_plugin_list($plugintype))) {
  174. throw new backup_step_exception('incorrect_plugin_name', array($plugintype, $pluginname));
  175. }
  176. // Check the requested subplugintype is a valid one.
  177. $subpluginsfile = core_component::get_component_directory($plugintype . '_' . $pluginname) . '/db/subplugins.php';
  178. if (!file_exists($subpluginsfile)) {
  179. throw new backup_step_exception('plugin_missing_subplugins_php_file', array($plugintype, $pluginname));
  180. }
  181. include($subpluginsfile);
  182. if (!array_key_exists($subplugintype, $subplugins)) {
  183. throw new backup_step_exception('incorrect_subplugin_type', $subplugintype);
  184. }
  185. // Arrived here, subplugin is correct, let's create the optigroup.
  186. $optigroupname = $subplugintype . '_' . $element->get_name() . '_subplugin';
  187. $optigroup = new backup_optigroup($optigroupname, null, $multiple);
  188. $element->add_child($optigroup); // Add optigroup to stay connected since beginning.
  189. // Every subplugin optionally can have a common/parent subplugin
  190. // class for shared stuff.
  191. $parentclass = 'backup_' . $plugintype . '_' . $pluginname . '_' . $subplugintype . '_subplugin';
  192. $parentfile = core_component::get_component_directory($plugintype . '_' . $pluginname) .
  193. '/backup/moodle2/' . $parentclass . '.class.php';
  194. if (file_exists($parentfile)) {
  195. require_once($parentfile);
  196. }
  197. // Get all the optigroup_elements, looking over all the subplugin dirs.
  198. $subpluginsdirs = core_component::get_plugin_list($subplugintype);
  199. foreach ($subpluginsdirs as $name => $subpluginsdir) {
  200. $classname = 'backup_' . $subplugintype . '_' . $name . '_subplugin';
  201. $backupfile = $subpluginsdir . '/backup/moodle2/' . $classname . '.class.php';
  202. if (file_exists($backupfile)) {
  203. require_once($backupfile);
  204. $backupsubplugin = new $classname($subplugintype, $name, $optigroup, $this);
  205. // Add subplugin returned structure to optigroup.
  206. $backupsubplugin->define_subplugin_structure($element->get_name());
  207. }
  208. }
  209. }
  210. /**
  211. * To conditionally decide if one step will be executed or no
  212. *
  213. * For steps needing to be executed conditionally, based in dynamic
  214. * conditions (at execution time vs at declaration time) you must
  215. * override this function. It will return true if the step must be
  216. * executed and false if not
  217. */
  218. protected function execute_condition() {
  219. return true;
  220. }
  221. /**
  222. * Define the structure to be processed by this backup step.
  223. *
  224. * @return backup_nested_element
  225. */
  226. abstract protected function define_structure();
  227. }