See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401] [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 * @package moodlecore 20 * @subpackage backup-dbops 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 * Non instantiable helper class providing DB support to the @backup_controller 27 * 28 * This class contains various static methods available for all the DB operations 29 * performed by the backup_controller class 30 * 31 * TODO: Finish phpdocs 32 */ 33 abstract class backup_controller_dbops extends backup_dbops { 34 35 /** 36 * @var string Backup id for cached backup_includes_files result. 37 */ 38 protected static $includesfilescachebackupid; 39 40 /** 41 * @var int Cached backup_includes_files result 42 */ 43 protected static $includesfilescache; 44 45 /** 46 * Send one backup controller to DB 47 * 48 * @param backup_controller $controller controller to send to DB 49 * @param string $checksum hash of the controller to be checked 50 * @param bool $includeobj to decide if the object itself must be updated (true) or no (false) 51 * @param bool $cleanobj to decide if the object itself must be cleaned (true) or no (false) 52 * @return int id of the controller record in the DB 53 * @throws backup_controller_exception|backup_dbops_exception 54 */ 55 public static function save_controller($controller, $checksum, $includeobj = true, $cleanobj = false) { 56 global $DB; 57 // Check we are going to save one backup_controller 58 if (! $controller instanceof backup_controller) { 59 throw new backup_controller_exception('backup_controller_expected'); 60 } 61 // Check checksum is ok. Only if we are including object info. Sounds silly but it isn't ;-). 62 if ($includeobj and !$controller->is_checksum_correct($checksum)) { 63 throw new backup_dbops_exception('backup_controller_dbops_saving_checksum_mismatch'); 64 } 65 // Cannot request to $includeobj and $cleanobj at the same time. 66 if ($includeobj and $cleanobj) { 67 throw new backup_dbops_exception('backup_controller_dbops_saving_cannot_include_and_delete'); 68 } 69 // Get all the columns 70 $rec = new stdclass(); 71 $rec->backupid = $controller->get_backupid(); 72 $rec->operation = $controller->get_operation(); 73 $rec->type = $controller->get_type(); 74 $rec->itemid = $controller->get_id(); 75 $rec->format = $controller->get_format(); 76 $rec->interactive = $controller->get_interactive(); 77 $rec->purpose = $controller->get_mode(); 78 $rec->userid = $controller->get_userid(); 79 $rec->status = $controller->get_status(); 80 $rec->execution = $controller->get_execution(); 81 $rec->executiontime= $controller->get_executiontime(); 82 $rec->checksum = $checksum; 83 // Serialize information 84 if ($includeobj) { 85 $rec->controller = base64_encode(serialize($controller)); 86 } else if ($cleanobj) { 87 $rec->controller = ''; 88 } 89 // Send it to DB 90 if ($recexists = $DB->get_record('backup_controllers', array('backupid' => $rec->backupid))) { 91 $rec->id = $recexists->id; 92 $rec->timemodified = time(); 93 $DB->update_record('backup_controllers', $rec); 94 } else { 95 $rec->timecreated = time(); 96 $rec->timemodified = 0; 97 $rec->id = $DB->insert_record('backup_controllers', $rec); 98 } 99 return $rec->id; 100 } 101 102 public static function load_controller($backupid) { 103 global $DB; 104 if (! $controllerrec = $DB->get_record('backup_controllers', array('backupid' => $backupid))) { 105 throw new backup_dbops_exception('backup_controller_dbops_nonexisting'); 106 } 107 $controller = unserialize(base64_decode($controllerrec->controller)); 108 if (!is_object($controller)) { 109 // The controller field of the table did not contain a serialized object. 110 // It is made empty after it has been used successfully, it is likely that 111 // the user has pressed the browser back button at some point. 112 throw new backup_dbops_exception('backup_controller_dbops_loading_invalid_controller'); 113 } 114 // Check checksum is ok. Sounds silly but it isn't ;-) 115 if (!$controller->is_checksum_correct($controllerrec->checksum)) { 116 throw new backup_dbops_exception('backup_controller_dbops_loading_checksum_mismatch'); 117 } 118 return $controller; 119 } 120 121 public static function create_backup_ids_temp_table($backupid) { 122 global $CFG, $DB; 123 $dbman = $DB->get_manager(); // We are going to use database_manager services 124 125 $xmldb_table = new xmldb_table('backup_ids_temp'); 126 $xmldb_table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 127 // Set default backupid (not needed but this enforce any missing backupid). That's hackery in action! 128 $xmldb_table->add_field('backupid', XMLDB_TYPE_CHAR, 32, null, XMLDB_NOTNULL, null, $backupid); 129 $xmldb_table->add_field('itemname', XMLDB_TYPE_CHAR, 160, null, XMLDB_NOTNULL, null, null); 130 $xmldb_table->add_field('itemid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null); 131 $xmldb_table->add_field('newitemid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0'); 132 $xmldb_table->add_field('parentitemid', XMLDB_TYPE_INTEGER, 10, null, null, null, null); 133 $xmldb_table->add_field('info', XMLDB_TYPE_TEXT, null, null, null, null, null); 134 $xmldb_table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); 135 $xmldb_table->add_key('backupid_itemname_itemid_uk', XMLDB_KEY_UNIQUE, array('backupid','itemname','itemid')); 136 $xmldb_table->add_index('backupid_parentitemid_ix', XMLDB_INDEX_NOTUNIQUE, array('backupid','itemname','parentitemid')); 137 $xmldb_table->add_index('backupid_itemname_newitemid_ix', XMLDB_INDEX_NOTUNIQUE, array('backupid','itemname','newitemid')); 138 139 $dbman->create_temp_table($xmldb_table); // And create it 140 141 } 142 143 public static function create_backup_files_temp_table($backupid) { 144 global $CFG, $DB; 145 $dbman = $DB->get_manager(); // We are going to use database_manager services 146 147 $xmldb_table = new xmldb_table('backup_files_temp'); 148 $xmldb_table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); 149 // Set default backupid (not needed but this enforce any missing backupid). That's hackery in action! 150 $xmldb_table->add_field('backupid', XMLDB_TYPE_CHAR, 32, null, XMLDB_NOTNULL, null, $backupid); 151 $xmldb_table->add_field('contextid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null); 152 $xmldb_table->add_field('component', XMLDB_TYPE_CHAR, 100, null, XMLDB_NOTNULL, null, null); 153 $xmldb_table->add_field('filearea', XMLDB_TYPE_CHAR, 50, null, XMLDB_NOTNULL, null, null); 154 $xmldb_table->add_field('itemid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null); 155 $xmldb_table->add_field('info', XMLDB_TYPE_TEXT, null, null, null, null, null); 156 $xmldb_table->add_field('newcontextid', XMLDB_TYPE_INTEGER, 10, null, null, null, null); 157 $xmldb_table->add_field('newitemid', XMLDB_TYPE_INTEGER, 10, null, null, null, null); 158 $xmldb_table->add_key('primary', XMLDB_KEY_PRIMARY, array('id')); 159 $xmldb_table->add_index('backupid_contextid_component_filearea_itemid_ix', XMLDB_INDEX_NOTUNIQUE, array('backupid','contextid','component','filearea','itemid')); 160 161 $dbman->create_temp_table($xmldb_table); // And create it 162 } 163 164 public static function drop_backup_ids_temp_table($backupid) { 165 global $DB; 166 $dbman = $DB->get_manager(); // We are going to use database_manager services 167 168 $targettablename = 'backup_ids_temp'; 169 if ($dbman->table_exists($targettablename)) { 170 $table = new xmldb_table($targettablename); 171 $dbman->drop_table($table); // And drop it 172 } 173 } 174 175 /** 176 * Decode the info field from backup_ids_temp or backup_files_temp. 177 * 178 * @param mixed $info The info field data to decode, may be an object or a simple integer. 179 * @return mixed The decoded information. For simple types it returns, for complex ones we decode. 180 */ 181 public static function decode_backup_temp_info($info) { 182 // We encode all data except null. 183 if ($info != null) { 184 return unserialize(gzuncompress(base64_decode($info))); 185 } 186 return $info; 187 } 188 189 /** 190 * Encode the info field for backup_ids_temp or backup_files_temp. 191 * 192 * @param mixed $info string The info field data to encode. 193 * @return string An encoded string of data or null if the input is null. 194 */ 195 public static function encode_backup_temp_info($info) { 196 // We encode if there is any information to keep the translations simpler. 197 if ($info != null) { 198 // We compress if possible. It reduces db, network and memory storage. The saving is greater than CPU compression cost. 199 // Compression level 1 is chosen has it produces good compression with the smallest possible overhead, see MDL-40618. 200 return base64_encode(gzcompress(serialize($info), 1)); 201 } 202 return $info; 203 } 204 205 /** 206 * Given one type and id from controller, return the corresponding courseid 207 */ 208 public static function get_courseid_from_type_id($type, $id) { 209 global $DB; 210 if ($type == backup::TYPE_1COURSE) { 211 return $id; // id is the course id 212 213 } else if ($type == backup::TYPE_1SECTION) { 214 if (! $courseid = $DB->get_field('course_sections', 'course', array('id' => $id))) { 215 throw new backup_dbops_exception('course_not_found_for_section', $id); 216 } 217 return $courseid; 218 } else if ($type == backup::TYPE_1ACTIVITY) { 219 if (! $courseid = $DB->get_field('course_modules', 'course', array('id' => $id))) { 220 throw new backup_dbops_exception('course_not_found_for_moduleid', $id); 221 } 222 return $courseid; 223 } 224 } 225 226 /** 227 * Given one activity task, return the activity information and related settings 228 * Used by get_moodle_backup_information() 229 */ 230 private static function get_activity_backup_information($task) { 231 232 $contentinfo = array( 233 'moduleid' => $task->get_moduleid(), 234 'sectionid' => $task->get_sectionid(), 235 'modulename' => $task->get_modulename(), 236 'title' => $task->get_name(), 237 'directory' => 'activities/' . $task->get_modulename() . '_' . $task->get_moduleid()); 238 239 // Now get activity settings 240 // Calculate prefix to find valid settings 241 $prefix = basename($contentinfo['directory']); 242 $settingsinfo = array(); 243 foreach ($task->get_settings() as $setting) { 244 // Discard ones without valid prefix 245 if (strpos($setting->get_name(), $prefix) !== 0) { 246 continue; 247 } 248 // Validate level is correct (activity) 249 if ($setting->get_level() != backup_setting::ACTIVITY_LEVEL) { 250 throw new backup_controller_exception('setting_not_activity_level', $setting); 251 } 252 $settinginfo = array( 253 'level' => 'activity', 254 'activity' => $prefix, 255 'name' => $setting->get_name(), 256 'value' => $setting->get_value()); 257 $settingsinfo[$setting->get_name()] = (object)$settinginfo; 258 } 259 return array($contentinfo, $settingsinfo); 260 } 261 262 /** 263 * Given one section task, return the section information and related settings 264 * Used by get_moodle_backup_information() 265 */ 266 private static function get_section_backup_information($task) { 267 268 $contentinfo = array( 269 'sectionid' => $task->get_sectionid(), 270 'title' => $task->get_name(), 271 'directory' => 'sections/' . 'section_' . $task->get_sectionid()); 272 273 // Now get section settings 274 // Calculate prefix to find valid settings 275 $prefix = basename($contentinfo['directory']); 276 $settingsinfo = array(); 277 foreach ($task->get_settings() as $setting) { 278 // Discard ones without valid prefix 279 if (strpos($setting->get_name(), $prefix) !== 0) { 280 continue; 281 } 282 // Validate level is correct (section) 283 if ($setting->get_level() != backup_setting::SECTION_LEVEL) { 284 throw new backup_controller_exception('setting_not_section_level', $setting); 285 } 286 $settinginfo = array( 287 'level' => 'section', 288 'section' => $prefix, 289 'name' => $setting->get_name(), 290 'value' => $setting->get_value()); 291 $settingsinfo[$setting->get_name()] = (object)$settinginfo; 292 } 293 return array($contentinfo, $settingsinfo); 294 } 295 296 /** 297 * Given one course task, return the course information and related settings 298 * Used by get_moodle_backup_information() 299 */ 300 private static function get_course_backup_information($task) { 301 302 $contentinfo = array( 303 'courseid' => $task->get_courseid(), 304 'title' => $task->get_name(), 305 'directory' => 'course'); 306 307 // Now get course settings 308 // Calculate prefix to find valid settings 309 $prefix = basename($contentinfo['directory']); 310 $settingsinfo = array(); 311 foreach ($task->get_settings() as $setting) { 312 // Discard ones without valid prefix 313 if (strpos($setting->get_name(), $prefix) !== 0) { 314 continue; 315 } 316 // Validate level is correct (course) 317 if ($setting->get_level() != backup_setting::COURSE_LEVEL) { 318 throw new backup_controller_exception('setting_not_course_level', $setting); 319 } 320 $settinginfo = array( 321 'level' => 'course', 322 'name' => $setting->get_name(), 323 'value' => $setting->get_value()); 324 $settingsinfo[$setting->get_name()] = (object)$settinginfo; 325 } 326 return array($contentinfo, $settingsinfo); 327 } 328 329 /** 330 * Given one root task, return the course information and related settings 331 * Used by get_moodle_backup_information() 332 */ 333 private static function get_root_backup_information($task) { 334 335 // Now get root settings 336 $settingsinfo = array(); 337 foreach ($task->get_settings() as $setting) { 338 // Validate level is correct (root) 339 if ($setting->get_level() != backup_setting::ROOT_LEVEL) { 340 throw new backup_controller_exception('setting_not_root_level', $setting); 341 } 342 $settinginfo = array( 343 'level' => 'root', 344 'name' => $setting->get_name(), 345 'value' => $setting->get_value()); 346 $settingsinfo[$setting->get_name()] = (object)$settinginfo; 347 } 348 return array(null, $settingsinfo); 349 } 350 351 /** 352 * Get details information for main moodle_backup.xml file, extracting it from 353 * the specified controller. 354 * 355 * If you specify the progress monitor, this will start a new progress section 356 * to track progress in processing (in case this task takes a long time). 357 * 358 * @param string $backupid Backup ID 359 * @param \core\progress\base $progress Optional progress monitor 360 */ 361 public static function get_moodle_backup_information($backupid, 362 \core\progress\base $progress = null) { 363 364 // Start tracking progress if required (for load_controller). 365 if ($progress) { 366 $progress->start_progress('get_moodle_backup_information', 2); 367 } 368 369 $detailsinfo = array(); // Information details 370 $contentsinfo= array(); // Information about backup contents 371 $settingsinfo= array(); // Information about backup settings 372 $bc = self::load_controller($backupid); // Load controller 373 374 // Note that we have loaded controller. 375 if ($progress) { 376 $progress->progress(1); 377 } 378 379 // Details info 380 $detailsinfo['id'] = $bc->get_id(); 381 $detailsinfo['backup_id'] = $bc->get_backupid(); 382 $detailsinfo['type'] = $bc->get_type(); 383 $detailsinfo['format'] = $bc->get_format(); 384 $detailsinfo['interactive'] = $bc->get_interactive(); 385 $detailsinfo['mode'] = $bc->get_mode(); 386 $detailsinfo['execution'] = $bc->get_execution(); 387 $detailsinfo['executiontime'] = $bc->get_executiontime(); 388 $detailsinfo['userid'] = $bc->get_userid(); 389 $detailsinfo['courseid'] = $bc->get_courseid(); 390 391 392 // Init content placeholders 393 $contentsinfo['activities'] = array(); 394 $contentsinfo['sections'] = array(); 395 $contentsinfo['course'] = array(); 396 397 // Get tasks and start nested progress. 398 $tasks = $bc->get_plan()->get_tasks(); 399 if ($progress) { 400 $progress->start_progress('get_moodle_backup_information', count($tasks)); 401 $done = 1; 402 } 403 404 // Contents info (extract information from tasks) 405 foreach ($tasks as $task) { 406 407 if ($task instanceof backup_activity_task) { // Activity task 408 409 if ($task->get_setting_value('included')) { // Only return info about included activities 410 list($contentinfo, $settings) = self::get_activity_backup_information($task); 411 $contentsinfo['activities'][] = $contentinfo; 412 $settingsinfo = array_merge($settingsinfo, $settings); 413 } 414 415 } else if ($task instanceof backup_section_task) { // Section task 416 417 if ($task->get_setting_value('included')) { // Only return info about included sections 418 list($contentinfo, $settings) = self::get_section_backup_information($task); 419 $contentsinfo['sections'][] = $contentinfo; 420 $settingsinfo = array_merge($settingsinfo, $settings); 421 } 422 423 } else if ($task instanceof backup_course_task) { // Course task 424 425 list($contentinfo, $settings) = self::get_course_backup_information($task); 426 $contentsinfo['course'][] = $contentinfo; 427 $settingsinfo = array_merge($settingsinfo, $settings); 428 429 } else if ($task instanceof backup_root_task) { // Root task 430 431 list($contentinfo, $settings) = self::get_root_backup_information($task); 432 $settingsinfo = array_merge($settingsinfo, $settings); 433 } 434 435 // Report task handled. 436 if ($progress) { 437 $progress->progress($done++); 438 } 439 } 440 441 $bc->destroy(); // Always need to destroy controller to handle circular references 442 443 // Finish progress reporting. 444 if ($progress) { 445 $progress->end_progress(); 446 $progress->end_progress(); 447 } 448 449 return array(array((object)$detailsinfo), $contentsinfo, $settingsinfo); 450 } 451 452 /** 453 * Update CFG->backup_version and CFG->backup_release if change in 454 * version is detected. 455 */ 456 public static function apply_version_and_release() { 457 global $CFG; 458 459 if ($CFG->backup_version < backup::VERSION) { 460 set_config('backup_version', backup::VERSION); 461 set_config('backup_release', backup::RELEASE); 462 } 463 } 464 465 /** 466 * Given the backupid, detect if the backup includes "mnet" remote users or no 467 */ 468 public static function backup_includes_mnet_remote_users($backupid) { 469 global $CFG, $DB; 470 471 $sql = "SELECT COUNT(*) 472 FROM {backup_ids_temp} b 473 JOIN {user} u ON u.id = b.itemid 474 WHERE b.backupid = ? 475 AND b.itemname = 'userfinal' 476 AND u.mnethostid != ?"; 477 $count = $DB->count_records_sql($sql, array($backupid, $CFG->mnet_localhost_id)); 478 return (int)(bool)$count; 479 } 480 481 /** 482 * Given the backupid, determine whether this backup should include 483 * files from the moodle file storage system. 484 * 485 * @param string $backupid The ID of the backup. 486 * @return int Indicates whether files should be included in backups. 487 */ 488 public static function backup_includes_files($backupid) { 489 // This function is called repeatedly in a backup with many files. 490 // Loading the controller is a nontrivial operation (in a large test 491 // backup it took 0.3 seconds), so we do a temporary cache of it within 492 // this request. 493 if (self::$includesfilescachebackupid === $backupid) { 494 return self::$includesfilescache; 495 } 496 497 // Load controller, get value, then destroy controller and return result. 498 self::$includesfilescachebackupid = $backupid; 499 $bc = self::load_controller($backupid); 500 self::$includesfilescache = $bc->get_include_files(); 501 $bc->destroy(); 502 return self::$includesfilescache; 503 } 504 505 /** 506 * Given the backupid, detect if the backup contains references to external contents 507 * 508 * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org} 509 * @return int 510 */ 511 public static function backup_includes_file_references($backupid) { 512 global $CFG, $DB; 513 514 $sql = "SELECT count(r.repositoryid) 515 FROM {files} f 516 LEFT JOIN {files_reference} r 517 ON r.id = f.referencefileid 518 JOIN {backup_ids_temp} bi 519 ON f.id = bi.itemid 520 WHERE bi.backupid = ? 521 AND bi.itemname = 'filefinal'"; 522 $count = $DB->count_records_sql($sql, array($backupid)); 523 return (int)(bool)$count; 524 } 525 526 /** 527 * Given the courseid, return some course related information we want to transport 528 * 529 * @param int $course the id of the course this backup belongs to 530 */ 531 public static function backup_get_original_course_info($courseid) { 532 global $DB; 533 return $DB->get_record('course', array('id' => $courseid), 'fullname, shortname, startdate, enddate, format'); 534 } 535 536 /** 537 * Sets the default values for the settings in a backup operation 538 * 539 * Based on the mode of the backup it will load proper defaults 540 * using {@link apply_admin_config_defaults}. 541 * 542 * @param backup_controller $controller 543 */ 544 public static function apply_config_defaults(backup_controller $controller) { 545 // Based on the mode of the backup (general, automated, import, hub...) 546 // decide the action to perform to get defaults loaded 547 $mode = $controller->get_mode(); 548 549 switch ($mode) { 550 case backup::MODE_GENERAL: 551 case backup::MODE_ASYNC: 552 // Load the general defaults 553 $settings = array( 554 'backup_general_users' => 'users', 555 'backup_general_anonymize' => 'anonymize', 556 'backup_general_role_assignments' => 'role_assignments', 557 'backup_general_activities' => 'activities', 558 'backup_general_blocks' => 'blocks', 559 'backup_general_filters' => 'filters', 560 'backup_general_comments' => 'comments', 561 'backup_general_badges' => 'badges', 562 'backup_general_calendarevents' => 'calendarevents', 563 'backup_general_userscompletion' => 'userscompletion', 564 'backup_general_logs' => 'logs', 565 'backup_general_histories' => 'grade_histories', 566 'backup_general_questionbank' => 'questionbank', 567 'backup_general_groups' => 'groups', 568 'backup_general_competencies' => 'competencies', 569 'backup_general_contentbankcontent' => 'contentbankcontent', 570 'backup_general_legacyfiles' => 'legacyfiles' 571 ); 572 self::apply_admin_config_defaults($controller, $settings, true); 573 break; 574 case backup::MODE_IMPORT: 575 // Load the import defaults. 576 $settings = array( 577 'backup_import_activities' => 'activities', 578 'backup_import_blocks' => 'blocks', 579 'backup_import_filters' => 'filters', 580 'backup_import_calendarevents' => 'calendarevents', 581 'backup_import_permissions' => 'permissions', 582 'backup_import_questionbank' => 'questionbank', 583 'backup_import_groups' => 'groups', 584 'backup_import_competencies' => 'competencies', 585 'backup_import_contentbankcontent' => 'contentbankcontent', 586 'backup_import_legacyfiles' => 'legacyfiles' 587 ); 588 self::apply_admin_config_defaults($controller, $settings, true); 589 if ((!$controller->get_interactive()) && 590 $controller->get_type() == backup::TYPE_1ACTIVITY) { 591 // This is duplicate - there is no concept of defaults - these settings must be on. 592 $settings = array( 593 'activities', 594 'blocks', 595 'filters', 596 'questionbank' 597 ); 598 self::force_enable_settings($controller, $settings); 599 } 600 break; 601 case backup::MODE_AUTOMATED: 602 // Load the automated defaults. 603 $settings = array( 604 'backup_auto_users' => 'users', 605 'backup_auto_role_assignments' => 'role_assignments', 606 'backup_auto_activities' => 'activities', 607 'backup_auto_blocks' => 'blocks', 608 'backup_auto_filters' => 'filters', 609 'backup_auto_comments' => 'comments', 610 'backup_auto_badges' => 'badges', 611 'backup_auto_calendarevents' => 'calendarevents', 612 'backup_auto_userscompletion' => 'userscompletion', 613 'backup_auto_logs' => 'logs', 614 'backup_auto_histories' => 'grade_histories', 615 'backup_auto_questionbank' => 'questionbank', 616 'backup_auto_groups' => 'groups', 617 'backup_auto_competencies' => 'competencies', 618 'backup_auto_contentbankcontent' => 'contentbankcontent', 619 'backup_auto_legacyfiles' => 'legacyfiles' 620 ); 621 self::apply_admin_config_defaults($controller, $settings, false); 622 break; 623 default: 624 // Nothing to do for other modes (HUB...). Some day we 625 // can define defaults (admin UI...) for them if we want to 626 } 627 } 628 629 /** 630 * Turn these settings on. No defaults from admin settings. 631 * 632 * @param backup_controller $controller 633 * @param array $settings a map from admin config names to setting names (Config name => Setting name) 634 */ 635 private static function force_enable_settings(backup_controller $controller, array $settings) { 636 $plan = $controller->get_plan(); 637 foreach ($settings as $config => $settingname) { 638 $value = true; 639 if ($plan->setting_exists($settingname)) { 640 $setting = $plan->get_setting($settingname); 641 // We do not allow this setting to be locked for a duplicate function. 642 if ($setting->get_status() !== base_setting::NOT_LOCKED) { 643 $setting->set_status(base_setting::NOT_LOCKED); 644 } 645 $setting->set_value($value); 646 $setting->set_status(base_setting::LOCKED_BY_CONFIG); 647 } else { 648 $controller->log('Unknown setting: ' . $setting, BACKUP::LOG_DEBUG); 649 } 650 } 651 } 652 653 /** 654 * Sets the controller settings default values from the admin config. 655 * 656 * @param backup_controller $controller 657 * @param array $settings a map from admin config names to setting names (Config name => Setting name) 658 * @param boolean $uselocks whether "locked" admin settings should be honoured 659 */ 660 private static function apply_admin_config_defaults(backup_controller $controller, array $settings, $uselocks) { 661 $plan = $controller->get_plan(); 662 foreach ($settings as $config=>$settingname) { 663 $value = get_config('backup', $config); 664 if ($value === false) { 665 // Ignore this because the config has not been set. get_config 666 // returns false if a setting doesn't exist, '0' is returned when 667 // the configuration is set to false. 668 $controller->log('Could not find a value for the config ' . $config, BACKUP::LOG_DEBUG); 669 continue; 670 } 671 $locked = $uselocks && (get_config('backup', $config.'_locked') == true); 672 if ($plan->setting_exists($settingname)) { 673 $setting = $plan->get_setting($settingname); 674 // We can only update the setting if it isn't already locked by config or permission. 675 if ($setting->get_status() !== base_setting::LOCKED_BY_CONFIG 676 && $setting->get_status() !== base_setting::LOCKED_BY_PERMISSION) { 677 $setting->set_value($value); 678 if ($locked) { 679 $setting->set_status(base_setting::LOCKED_BY_CONFIG); 680 } 681 } 682 } else { 683 $controller->log('Unknown setting: ' . $setting, BACKUP::LOG_DEBUG); 684 } 685 } 686 } 687 688 /** 689 * Get the progress details of a backup operation. 690 * Get backup records directly from database, if the backup has successfully completed 691 * there will be no controller object to load. 692 * 693 * @param string $backupid The backup id to query. 694 * @return array $progress The backup progress details. 695 */ 696 public static function get_progress($backupid) { 697 global $DB; 698 699 $progress = array(); 700 $backuprecord = $DB->get_record( 701 'backup_controllers', 702 array('backupid' => $backupid), 703 'status, progress, operation', 704 MUST_EXIST); 705 706 $status = $backuprecord->status; 707 $progress = $backuprecord->progress; 708 $operation = $backuprecord->operation; 709 710 $progress = array('status' => $status, 'progress' => $progress, 'backupid' => $backupid, 'operation' => $operation); 711 712 return $progress; 713 } 714 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body