[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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-controller 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 * Class implementing the controller of any backup process 27 * 28 * This final class is in charge of controlling all the backup architecture, for any 29 * type of backup. Based in type, format, interactivity and target, it stores the 30 * whole execution plan and settings that will be used later by the @backup_worker, 31 * applies all the defaults, performs all the security contraints and is in charge 32 * of handling the ui if necessary. Also logging strategy is defined here. 33 * 34 * Note the class is 100% neutral and usable for *any* backup. It just stores/requests 35 * all the needed information from other backup classes in order to have everything well 36 * structured in order to allow the @backup_worker classes to do their job. 37 * 38 * In other words, a mammoth class, but don't worry, practically everything is delegated/ 39 * aggregated!) 40 * 41 * TODO: Finish phpdocs 42 */ 43 class backup_controller extends base_controller { 44 45 protected $backupid; // Unique identificator for this backup 46 47 protected $type; // Type of backup (activity, section, course) 48 protected $id; // Course/section/course_module id to backup 49 protected $courseid; // courseid where the id belongs to 50 protected $format; // Format of backup (moodle, imscc) 51 protected $interactive; // yes/no 52 protected $mode; // Purpose of the backup (default settings) 53 protected $userid; // user id executing the backup 54 protected $operation; // Type of operation (backup/restore) 55 56 protected $status; // Current status of the controller (created, planned, configured...) 57 58 protected $plan; // Backup execution plan 59 protected $includefiles; // Whether this backup includes files or not. 60 61 protected $execution; // inmediate/delayed 62 protected $executiontime; // epoch time when we want the backup to be executed (requires cron to run) 63 64 protected $destination; // Destination chain object (fs_moodle, fs_os, db, email...) 65 66 protected $checksum; // Cache @checksumable results for lighter @is_checksum_correct() uses 67 68 /** 69 * Constructor for the backup controller class. 70 * 71 * @param int $type Type of the backup; One of backup::TYPE_1COURSE, TYPE_1SECTION, TYPE_1ACTIVITY 72 * @param int $id The ID of the item to backup; e.g the course id 73 * @param int $format The backup format to use; Most likely backup::FORMAT_MOODLE 74 * @param bool $interactive Whether this backup will require user interaction; backup::INTERACTIVE_YES or INTERACTIVE_NO 75 * @param int $mode One of backup::MODE_GENERAL, MODE_IMPORT, MODE_SAMESITE, MODE_HUB, MODE_AUTOMATED 76 * @param int $userid The id of the user making the backup 77 */ 78 public function __construct($type, $id, $format, $interactive, $mode, $userid){ 79 $this->type = $type; 80 $this->id = $id; 81 $this->courseid = backup_controller_dbops::get_courseid_from_type_id($this->type, $this->id); 82 $this->format = $format; 83 $this->interactive = $interactive; 84 $this->mode = $mode; 85 $this->userid = $userid; 86 87 // Apply some defaults 88 $this->execution = backup::EXECUTION_INMEDIATE; 89 $this->operation = backup::OPERATION_BACKUP; 90 $this->executiontime = 0; 91 $this->checksum = ''; 92 93 // Apply current backup version and release if necessary 94 backup_controller_dbops::apply_version_and_release(); 95 96 // Check format and type are correct 97 backup_check::check_format_and_type($this->format, $this->type); 98 99 // Check id is correct 100 backup_check::check_id($this->type, $this->id); 101 102 // Check user is correct 103 backup_check::check_user($this->userid); 104 105 // Calculate unique $backupid 106 $this->calculate_backupid(); 107 108 // Default logger chain (based on interactive/execution) 109 $this->logger = backup_factory::get_logger_chain($this->interactive, $this->execution, $this->backupid); 110 111 // By default there is no progress reporter. Interfaces that wish to 112 // display progress must set it. 113 $this->progress = new \core\progress\none(); 114 115 // Instantiate the output_controller singleton and active it if interactive and inmediate 116 $oc = output_controller::get_instance(); 117 if ($this->interactive == backup::INTERACTIVE_YES && $this->execution == backup::EXECUTION_INMEDIATE) { 118 $oc->set_active(true); 119 } 120 121 $this->log('instantiating backup controller', backup::LOG_INFO, $this->backupid); 122 123 // Default destination chain (based on type/mode/execution) 124 $this->destination = backup_factory::get_destination_chain($this->type, $this->id, $this->mode, $this->execution); 125 126 // Set initial status 127 $this->set_status(backup::STATUS_CREATED); 128 129 // Load plan (based on type/format) 130 $this->load_plan(); 131 132 // Apply all default settings (based on type/format/mode) 133 $this->apply_defaults(); 134 135 // Perform all initial security checks and apply (2nd param) them to settings automatically 136 backup_check::check_security($this, true); 137 138 // Set status based on interactivity 139 if ($this->interactive == backup::INTERACTIVE_YES) { 140 $this->set_status(backup::STATUS_SETTING_UI); 141 } else { 142 $this->set_status(backup::STATUS_AWAITING); 143 } 144 } 145 146 /** 147 * Clean structures used by the backup_controller 148 * 149 * This method clean various structures used by the backup_controller, 150 * destroying them in an ordered way, so their memory will be gc properly 151 * by PHP (mainly circular references). 152 * 153 * Note that, while it's not mandatory to execute this method, it's highly 154 * recommended to do so, specially in scripts performing multiple operations 155 * (like the automated backups) or the system will run out of memory after 156 * a few dozens of backups) 157 */ 158 public function destroy() { 159 // Only need to destroy circulars under the plan. Delegate to it. 160 $this->plan->destroy(); 161 // Loggers may have also chained references, destroy them. Also closing resources when needed. 162 $this->logger->destroy(); 163 } 164 165 public function finish_ui() { 166 if ($this->status != backup::STATUS_SETTING_UI) { 167 throw new backup_controller_exception('cannot_finish_ui_if_not_setting_ui'); 168 } 169 $this->set_status(backup::STATUS_AWAITING); 170 } 171 172 public function process_ui_event() { 173 174 // Perform security checks throwing exceptions (2nd param) if something is wrong 175 backup_check::check_security($this, false); 176 } 177 178 public function set_status($status) { 179 // Note: never save_controller() with the object info after STATUS_EXECUTING or the whole controller, 180 // containing all the steps will be sent to DB. 100% (monster) useless. 181 $this->log('setting controller status to', backup::LOG_DEBUG, $status); 182 // TODO: Check it's a correct status. 183 $this->status = $status; 184 // Ensure that, once set to backup::STATUS_AWAITING, controller is stored in DB. 185 if ($status == backup::STATUS_AWAITING) { 186 $this->save_controller(); 187 $tbc = self::load_controller($this->backupid); 188 $this->logger = $tbc->logger; // wakeup loggers 189 $tbc->plan->destroy(); // Clean plan controller structures, keeping logger alive. 190 191 } else if ($status == backup::STATUS_FINISHED_OK) { 192 // If the operation has ended without error (backup::STATUS_FINISHED_OK) 193 // proceed by cleaning the object from database. MDL-29262. 194 $this->save_controller(false, true); 195 } 196 } 197 198 public function set_execution($execution, $executiontime = 0) { 199 $this->log('setting controller execution', backup::LOG_DEBUG); 200 // TODO: Check valid execution mode 201 // TODO: Check time in future 202 // TODO: Check time = 0 if inmediate 203 $this->execution = $execution; 204 $this->executiontime = $executiontime; 205 206 // Default destination chain (based on type/mode/execution) 207 $this->destination = backup_factory::get_destination_chain($this->type, $this->id, $this->mode, $this->execution); 208 209 // Default logger chain (based on interactive/execution) 210 $this->logger = backup_factory::get_logger_chain($this->interactive, $this->execution, $this->backupid); 211 } 212 213 // checksumable interface methods 214 215 public function calculate_checksum() { 216 // Reset current checksum to take it out from calculations! 217 $this->checksum = ''; 218 // Init checksum 219 $tempchecksum = md5('backupid-' . $this->backupid . 220 'type-' . $this->type . 221 'id-' . $this->id . 222 'format-' . $this->format . 223 'interactive-'. $this->interactive . 224 'mode-' . $this->mode . 225 'userid-' . $this->userid . 226 'operation-' . $this->operation . 227 'status-' . $this->status . 228 'execution-' . $this->execution . 229 'plan-' . backup_general_helper::array_checksum_recursive(array($this->plan)) . 230 'destination-'. backup_general_helper::array_checksum_recursive(array($this->destination)) . 231 'logger-' . backup_general_helper::array_checksum_recursive(array($this->logger))); 232 $this->log('calculating controller checksum', backup::LOG_DEBUG, $tempchecksum); 233 return $tempchecksum; 234 } 235 236 public function is_checksum_correct($checksum) { 237 return $this->checksum === $checksum; 238 } 239 240 public function get_backupid() { 241 return $this->backupid; 242 } 243 244 public function get_type() { 245 return $this->type; 246 } 247 248 /** 249 * Returns the current value of the include_files setting. 250 * This setting is intended to ensure that files are not included in 251 * generated backups. 252 * 253 * @return int Indicates whether files should be included in backups. 254 */ 255 public function get_include_files() { 256 return $this->includefiles; 257 } 258 259 public function get_operation() { 260 return $this->operation; 261 } 262 263 public function get_id() { 264 return $this->id; 265 } 266 267 public function get_courseid() { 268 return $this->courseid; 269 } 270 271 public function get_format() { 272 return $this->format; 273 } 274 275 public function get_interactive() { 276 return $this->interactive; 277 } 278 279 public function get_mode() { 280 return $this->mode; 281 } 282 283 public function get_userid() { 284 return $this->userid; 285 } 286 287 public function get_status() { 288 return $this->status; 289 } 290 291 public function get_execution() { 292 return $this->execution; 293 } 294 295 public function get_executiontime() { 296 return $this->executiontime; 297 } 298 299 /** 300 * @return backup_plan 301 */ 302 public function get_plan() { 303 return $this->plan; 304 } 305 306 /** 307 * Executes the backup 308 * @return void Throws and exception of completes 309 */ 310 public function execute_plan() { 311 // Basic/initial prevention against time/memory limits 312 core_php_time_limit::raise(1 * 60 * 60); // 1 hour for 1 course initially granted 313 raise_memory_limit(MEMORY_EXTRA); 314 // If this is not a course backup, inform the plan we are not 315 // including all the activities for sure. This will affect any 316 // task/step executed conditionally to stop including information 317 // for section and activity backup. MDL-28180. 318 if ($this->get_type() !== backup::TYPE_1COURSE) { 319 $this->log('notifying plan about excluded activities by type', backup::LOG_DEBUG); 320 $this->plan->set_excluding_activities(); 321 } 322 return $this->plan->execute(); 323 } 324 325 public function get_results() { 326 return $this->plan->get_results(); 327 } 328 329 /** 330 * Save controller information 331 * 332 * @param bool $includeobj to decide if the object itself must be updated (true) or no (false) 333 * @param bool $cleanobj to decide if the object itself must be cleaned (true) or no (false) 334 */ 335 public function save_controller($includeobj = true, $cleanobj = false) { 336 // Going to save controller to persistent storage, calculate checksum for later checks and save it 337 // TODO: flag the controller as NA. Any operation on it should be forbidden util loaded back 338 $this->log('saving controller to db', backup::LOG_DEBUG); 339 if ($includeobj ) { // Only calculate checksum if we are going to include the object. 340 $this->checksum = $this->calculate_checksum(); 341 } 342 backup_controller_dbops::save_controller($this, $this->checksum, $includeobj, $cleanobj); 343 } 344 345 public static function load_controller($backupid) { 346 // Load controller from persistent storage 347 // TODO: flag the controller as available. Operations on it can continue 348 $controller = backup_controller_dbops::load_controller($backupid); 349 $controller->log('loading controller from db', backup::LOG_DEBUG); 350 return $controller; 351 } 352 353 // Protected API starts here 354 355 protected function calculate_backupid() { 356 // Current epoch time + type + id + format + interactive + mode + userid + operation 357 // should be unique enough. Add one random part at the end 358 $this->backupid = md5(time() . '-' . $this->type . '-' . $this->id . '-' . $this->format . '-' . 359 $this->interactive . '-' . $this->mode . '-' . $this->userid . '-' . 360 $this->operation . '-' . random_string(20)); 361 } 362 363 protected function load_plan() { 364 $this->log('loading controller plan', backup::LOG_DEBUG); 365 $this->plan = new backup_plan($this); 366 $this->plan->build(); // Build plan for this controller 367 $this->set_status(backup::STATUS_PLANNED); 368 } 369 370 protected function apply_defaults() { 371 $this->log('applying plan defaults', backup::LOG_DEBUG); 372 backup_controller_dbops::apply_config_defaults($this); 373 $this->set_status(backup::STATUS_CONFIGURED); 374 $this->set_include_files(); 375 } 376 377 /** 378 * Set the initial value for the include_files setting. 379 * 380 * @see backup_controller::get_include_files for further information on the purpose of this setting. 381 * @return int Indicates whether files should be included in backups. 382 */ 383 protected function set_include_files() { 384 // We normally include files. 385 $includefiles = true; 386 387 // In an import, we don't need to include files. 388 if ($this->get_mode() === backup::MODE_IMPORT) { 389 $includefiles = false; 390 } 391 392 // When a backup is intended for the same site, we don't need to include the files. 393 // Note, this setting is only used for duplication of an entire course. 394 if ($this->get_mode() === backup::MODE_SAMESITE) { 395 $includefiles = false; 396 } 397 398 $this->includefiles = (int) $includefiles; 399 $this->log("setting file inclusion to {$this->includefiles}", backup::LOG_DEBUG); 400 return $this->includefiles; 401 } 402 } 403 404 /* 405 * Exception class used by all the @backup_controller stuff 406 */ 407 class backup_controller_exception extends backup_exception { 408 409 public function __construct($errorcode, $a=NULL, $debuginfo=null) { 410 parent::__construct($errorcode, $a, $debuginfo); 411 } 412 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |