|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00033 class create_and_clean_temp_stuff extends backup_execution_step { 00034 00035 protected function define_execution() { 00036 backup_helper::check_and_create_backup_dir($this->get_backupid());// Create backup temp dir 00037 backup_helper::clear_backup_dir($this->get_backupid()); // Empty temp dir, just in case 00038 backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60)); // Delete > 4 hours temp dirs 00039 backup_controller_dbops::create_backup_ids_temp_table($this->get_backupid()); // Create ids temp table 00040 } 00041 } 00042 00050 class drop_and_clean_temp_stuff extends backup_execution_step { 00051 00052 protected $skipcleaningtempdir = false; 00053 00054 protected function define_execution() { 00055 global $CFG; 00056 00057 backup_controller_dbops::drop_backup_ids_temp_table($this->get_backupid()); // Drop ids temp table 00058 backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60)); // Delete > 4 hours temp dirs 00059 // Delete temp dir conditionally: 00060 // 1) If $CFG->keeptempdirectoriesonbackup is not enabled 00061 // 2) If backup temp dir deletion has been marked to be avoided 00062 if (empty($CFG->keeptempdirectoriesonbackup) && !$this->skipcleaningtempdir) { 00063 backup_helper::delete_backup_dir($this->get_backupid()); // Empty backup dir 00064 } 00065 } 00066 00067 public function skip_cleaning_temp_dir($skip) { 00068 $this->skipcleaningtempdir = $skip; 00069 } 00070 } 00071 00075 class create_taskbasepath_directory extends backup_execution_step { 00076 00077 protected function define_execution() { 00078 global $CFG; 00079 $basepath = $this->task->get_taskbasepath(); 00080 if (!check_dir_exists($basepath, true, true)) { 00081 throw new backup_step_exception('cannot_create_taskbasepath_directory', $basepath); 00082 } 00083 } 00084 } 00085 00091 abstract class backup_activity_structure_step extends backup_structure_step { 00092 00102 protected function add_subplugin_structure($subplugintype, $element, $multiple) { 00103 00104 global $CFG; 00105 00106 // Check the requested subplugintype is a valid one 00107 $subpluginsfile = $CFG->dirroot . '/mod/' . $this->task->get_modulename() . '/db/subplugins.php'; 00108 if (!file_exists($subpluginsfile)) { 00109 throw new backup_step_exception('activity_missing_subplugins_php_file', $this->task->get_modulename()); 00110 } 00111 include($subpluginsfile); 00112 if (!array_key_exists($subplugintype, $subplugins)) { 00113 throw new backup_step_exception('incorrect_subplugin_type', $subplugintype); 00114 } 00115 00116 // Arrived here, subplugin is correct, let's create the optigroup 00117 $optigroupname = $subplugintype . '_' . $element->get_name() . '_subplugin'; 00118 $optigroup = new backup_optigroup($optigroupname, null, $multiple); 00119 $element->add_child($optigroup); // Add optigroup to stay connected since beginning 00120 00121 // Get all the optigroup_elements, looking across all the subplugin dirs 00122 $subpluginsdirs = get_plugin_list($subplugintype); 00123 foreach ($subpluginsdirs as $name => $subpluginsdir) { 00124 $classname = 'backup_' . $subplugintype . '_' . $name . '_subplugin'; 00125 $backupfile = $subpluginsdir . '/backup/moodle2/' . $classname . '.class.php'; 00126 if (file_exists($backupfile)) { 00127 require_once($backupfile); 00128 $backupsubplugin = new $classname($subplugintype, $name, $optigroup, $this); 00129 // Add subplugin returned structure to optigroup 00130 $backupsubplugin->define_subplugin_structure($element->get_name()); 00131 } 00132 } 00133 } 00134 00139 public function get_task() { 00140 return $this->task; 00141 } 00142 00147 protected function prepare_activity_structure($activitystructure) { 00148 00149 // Create the wrap element 00150 $activity = new backup_nested_element('activity', array('id', 'moduleid', 'modulename', 'contextid'), null); 00151 00152 // Build the tree 00153 $activity->add_child($activitystructure); 00154 00155 // Set the source 00156 $activityarr = array((object)array( 00157 'id' => $this->task->get_activityid(), 00158 'moduleid' => $this->task->get_moduleid(), 00159 'modulename' => $this->task->get_modulename(), 00160 'contextid' => $this->task->get_contextid())); 00161 00162 $activity->set_source_array($activityarr); 00163 00164 // Return the root element (activity) 00165 return $activity; 00166 } 00167 } 00168 00173 abstract class backup_questions_activity_structure_step extends backup_activity_structure_step { 00174 00179 protected function add_question_usages($element, $usageidname) { 00180 global $CFG; 00181 require_once($CFG->dirroot . '/question/engine/lib.php'); 00182 00183 // Check $element is one nested_backup_element 00184 if (! $element instanceof backup_nested_element) { 00185 throw new backup_step_exception('question_states_bad_parent_element', $element); 00186 } 00187 if (! $element->get_final_element($usageidname)) { 00188 throw new backup_step_exception('question_states_bad_question_attempt_element', $usageidname); 00189 } 00190 00191 $quba = new backup_nested_element('question_usage', array('id'), 00192 array('component', 'preferredbehaviour')); 00193 00194 $qas = new backup_nested_element('question_attempts'); 00195 $qa = new backup_nested_element('question_attempt', array('id'), array( 00196 'slot', 'behaviour', 'questionid', 'maxmark', 'minfraction', 00197 'flagged', 'questionsummary', 'rightanswer', 'responsesummary', 00198 'timemodified')); 00199 00200 $steps = new backup_nested_element('steps'); 00201 $step = new backup_nested_element('step', array('id'), array( 00202 'sequencenumber', 'state', 'fraction', 'timecreated', 'userid')); 00203 00204 $response = new backup_nested_element('response'); 00205 $variable = new backup_nested_element('variable', null, array('name', 'value')); 00206 00207 // Build the tree 00208 $element->add_child($quba); 00209 $quba->add_child($qas); 00210 $qas->add_child($qa); 00211 $qa->add_child($steps); 00212 $steps->add_child($step); 00213 $step->add_child($response); 00214 $response->add_child($variable); 00215 00216 // Set the sources 00217 $quba->set_source_table('question_usages', 00218 array('id' => '../' . $usageidname)); 00219 $qa->set_source_sql(' 00220 SELECT * 00221 FROM {question_attempts} 00222 WHERE questionusageid = :questionusageid 00223 ORDER BY slot', 00224 array('questionusageid' => backup::VAR_PARENTID)); 00225 $step->set_source_sql(' 00226 SELECT * 00227 FROM {question_attempt_steps} 00228 WHERE questionattemptid = :questionattemptid 00229 ORDER BY sequencenumber', 00230 array('questionattemptid' => backup::VAR_PARENTID)); 00231 $variable->set_source_table('question_attempt_step_data', 00232 array('attemptstepid' => backup::VAR_PARENTID)); 00233 00234 // Annotate ids 00235 $qa->annotate_ids('question', 'questionid'); 00236 $step->annotate_ids('user', 'userid'); 00237 00238 // Annotate files 00239 $fileareas = question_engine::get_all_response_file_areas(); 00240 foreach ($fileareas as $filearea) { 00241 $step->annotate_files('question', $filearea, 'id'); 00242 } 00243 } 00244 } 00245 00246 00252 class backup_calculate_question_categories extends backup_execution_step { 00253 00254 protected function define_execution() { 00255 backup_question_dbops::calculate_question_categories($this->get_backupid(), $this->task->get_contextid()); 00256 } 00257 } 00258 00263 class backup_delete_temp_questions extends backup_execution_step { 00264 00265 protected function define_execution() { 00266 backup_question_dbops::delete_temp_questions($this->get_backupid()); 00267 } 00268 } 00269 00274 abstract class backup_block_structure_step extends backup_structure_step { 00275 00276 protected function prepare_block_structure($blockstructure) { 00277 00278 // Create the wrap element 00279 $block = new backup_nested_element('block', array('id', 'blockname', 'contextid'), null); 00280 00281 // Build the tree 00282 $block->add_child($blockstructure); 00283 00284 // Set the source 00285 $blockarr = array((object)array( 00286 'id' => $this->task->get_blockid(), 00287 'blockname' => $this->task->get_blockname(), 00288 'contextid' => $this->task->get_contextid())); 00289 00290 $block->set_source_array($blockarr); 00291 00292 // Return the root element (block) 00293 return $block; 00294 } 00295 } 00296 00302 class backup_module_structure_step extends backup_structure_step { 00303 00304 protected function define_structure() { 00305 00306 // Define each element separated 00307 00308 $module = new backup_nested_element('module', array('id', 'version'), array( 00309 'modulename', 'sectionid', 'sectionnumber', 'idnumber', 00310 'added', 'score', 'indent', 'visible', 00311 'visibleold', 'groupmode', 'groupingid', 'groupmembersonly', 00312 'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected', 00313 'availablefrom', 'availableuntil', 'showavailability', 'showdescription')); 00314 00315 $availinfo = new backup_nested_element('availability_info'); 00316 $availability = new backup_nested_element('availability', array('id'), array( 00317 'sourcecmid', 'requiredcompletion', 'gradeitemid', 'grademin', 'grademax')); 00318 00319 // attach format plugin structure to $module element, only one allowed 00320 $this->add_plugin_structure('format', $module, false); 00321 00322 // attach plagiarism plugin structure to $module element, there can be potentially 00323 // many plagiarism plugins storing information about this course 00324 $this->add_plugin_structure('plagiarism', $module, true); 00325 00326 // Define the tree 00327 $module->add_child($availinfo); 00328 $availinfo->add_child($availability); 00329 00330 // Set the sources 00331 00332 $module->set_source_sql(' 00333 SELECT cm.*, m.version, m.name AS modulename, s.id AS sectionid, s.section AS sectionnumber 00334 FROM {course_modules} cm 00335 JOIN {modules} m ON m.id = cm.module 00336 JOIN {course_sections} s ON s.id = cm.section 00337 WHERE cm.id = ?', array(backup::VAR_MODID)); 00338 00339 $availability->set_source_table('course_modules_availability', array('coursemoduleid' => backup::VAR_MODID)); 00340 00341 // Define annotations 00342 $module->annotate_ids('grouping', 'groupingid'); 00343 00344 // Return the root element ($module) 00345 return $module; 00346 } 00347 } 00348 00353 class backup_section_structure_step extends backup_structure_step { 00354 00355 protected function define_structure() { 00356 00357 // Define each element separated 00358 00359 $section = new backup_nested_element('section', array('id'), array( 00360 'number', 'name', 'summary', 'summaryformat', 'sequence', 'visible')); 00361 00362 // attach format plugin structure to $section element, only one allowed 00363 $this->add_plugin_structure('format', $section, false); 00364 00365 // Define sources 00366 00367 $section->set_source_table('course_sections', array('id' => backup::VAR_SECTIONID)); 00368 00369 // Aliases 00370 $section->set_source_alias('section', 'number'); 00371 00372 // Set annotations 00373 $section->annotate_files('course', 'section', 'id'); 00374 00375 return $section; 00376 } 00377 } 00378 00384 class backup_course_structure_step extends backup_structure_step { 00385 00386 protected function define_structure() { 00387 global $DB; 00388 00389 // Define each element separated 00390 00391 $course = new backup_nested_element('course', array('id', 'contextid'), array( 00392 'shortname', 'fullname', 'idnumber', 00393 'summary', 'summaryformat', 'format', 'showgrades', 00394 'newsitems', 'startdate', 'numsections', 00395 'marker', 'maxbytes', 'legacyfiles', 'showreports', 00396 'visible', 'hiddensections', 'groupmode', 'groupmodeforce', 00397 'defaultgroupingid', 'lang', 'theme', 00398 'timecreated', 'timemodified', 00399 'requested', 'restrictmodules', 00400 'enablecompletion', 'completionstartonenrol', 'completionnotify')); 00401 00402 $category = new backup_nested_element('category', array('id'), array( 00403 'name', 'description')); 00404 00405 $tags = new backup_nested_element('tags'); 00406 00407 $tag = new backup_nested_element('tag', array('id'), array( 00408 'name', 'rawname')); 00409 00410 $allowedmodules = new backup_nested_element('allowed_modules'); 00411 00412 $module = new backup_nested_element('module', array(), array('modulename')); 00413 00414 // attach format plugin structure to $course element, only one allowed 00415 $this->add_plugin_structure('format', $course, false); 00416 00417 // attach theme plugin structure to $course element; multiple themes can 00418 // save course data (in case of user theme, legacy theme, etc) 00419 $this->add_plugin_structure('theme', $course, true); 00420 00421 // attach general report plugin structure to $course element; multiple 00422 // reports can save course data if required 00423 $this->add_plugin_structure('report', $course, true); 00424 00425 // attach course report plugin structure to $course element; multiple 00426 // course reports can save course data if required 00427 $this->add_plugin_structure('coursereport', $course, true); 00428 00429 // attach plagiarism plugin structure to $course element, there can be potentially 00430 // many plagiarism plugins storing information about this course 00431 $this->add_plugin_structure('plagiarism', $course, true); 00432 00433 // Build the tree 00434 00435 $course->add_child($category); 00436 00437 $course->add_child($tags); 00438 $tags->add_child($tag); 00439 00440 $course->add_child($allowedmodules); 00441 $allowedmodules->add_child($module); 00442 00443 // Set the sources 00444 00445 $courserec = $DB->get_record('course', array('id' => $this->task->get_courseid())); 00446 $courserec->contextid = $this->task->get_contextid(); 00447 00448 $course->set_source_array(array($courserec)); 00449 00450 $categoryrec = $DB->get_record('course_categories', array('id' => $courserec->category)); 00451 00452 $category->set_source_array(array($categoryrec)); 00453 00454 $tag->set_source_sql('SELECT t.id, t.name, t.rawname 00455 FROM {tag} t 00456 JOIN {tag_instance} ti ON ti.tagid = t.id 00457 WHERE ti.itemtype = ? 00458 AND ti.itemid = ?', array( 00459 backup_helper::is_sqlparam('course'), 00460 backup::VAR_PARENTID)); 00461 00462 $module->set_source_sql('SELECT m.name AS modulename 00463 FROM {modules} m 00464 JOIN {course_allowed_modules} cam ON m.id = cam.module 00465 WHERE course = ?', array(backup::VAR_COURSEID)); 00466 00467 // Some annotations 00468 00469 $course->annotate_ids('grouping', 'defaultgroupingid'); 00470 00471 $course->annotate_files('course', 'summary', null); 00472 $course->annotate_files('course', 'legacy', null); 00473 00474 // Return root element ($course) 00475 00476 return $course; 00477 } 00478 } 00479 00483 class backup_enrolments_structure_step extends backup_structure_step { 00484 00485 protected function define_structure() { 00486 00487 // To know if we are including users 00488 $users = $this->get_setting_value('users'); 00489 00490 // Define each element separated 00491 00492 $enrolments = new backup_nested_element('enrolments'); 00493 00494 $enrols = new backup_nested_element('enrols'); 00495 00496 $enrol = new backup_nested_element('enrol', array('id'), array( 00497 'enrol', 'status', 'sortorder', 'name', 'enrolperiod', 'enrolstartdate', 00498 'enrolenddate', 'expirynotify', 'expirytreshold', 'notifyall', 00499 'password', 'cost', 'currency', 'roleid', 'customint1', 'customint2', 'customint3', 00500 'customint4', 'customchar1', 'customchar2', 'customdec1', 'customdec2', 00501 'customtext1', 'customtext2', 'timecreated', 'timemodified')); 00502 00503 $userenrolments = new backup_nested_element('user_enrolments'); 00504 00505 $enrolment = new backup_nested_element('enrolment', array('id'), array( 00506 'status', 'userid', 'timestart', 'timeend', 'modifierid', 00507 'timemodified')); 00508 00509 // Build the tree 00510 $enrolments->add_child($enrols); 00511 $enrols->add_child($enrol); 00512 $enrol->add_child($userenrolments); 00513 $userenrolments->add_child($enrolment); 00514 00515 // Define sources 00516 00517 $enrol->set_source_table('enrol', array('courseid' => backup::VAR_COURSEID)); 00518 00519 // User enrolments only added only if users included 00520 if ($users) { 00521 $enrolment->set_source_table('user_enrolments', array('enrolid' => backup::VAR_PARENTID)); 00522 $enrolment->annotate_ids('user', 'userid'); 00523 } 00524 00525 $enrol->annotate_ids('role', 'roleid'); 00526 00527 //TODO: let plugins annotate custom fields too and add more children 00528 00529 return $enrolments; 00530 } 00531 } 00532 00537 class backup_roles_structure_step extends backup_structure_step { 00538 00539 protected function define_structure() { 00540 00541 // To know if we are including role assignments 00542 $roleassignments = $this->get_setting_value('role_assignments'); 00543 00544 // Define each element separated 00545 00546 $roles = new backup_nested_element('roles'); 00547 00548 $overrides = new backup_nested_element('role_overrides'); 00549 00550 $override = new backup_nested_element('override', array('id'), array( 00551 'roleid', 'capability', 'permission', 'timemodified', 00552 'modifierid')); 00553 00554 $assignments = new backup_nested_element('role_assignments'); 00555 00556 $assignment = new backup_nested_element('assignment', array('id'), array( 00557 'roleid', 'userid', 'timemodified', 'modifierid', 'component', 'itemid', 00558 'sortorder')); 00559 00560 // Build the tree 00561 $roles->add_child($overrides); 00562 $roles->add_child($assignments); 00563 00564 $overrides->add_child($override); 00565 $assignments->add_child($assignment); 00566 00567 // Define sources 00568 00569 $override->set_source_table('role_capabilities', array('contextid' => backup::VAR_CONTEXTID)); 00570 00571 // Assignments only added if specified 00572 if ($roleassignments) { 00573 $assignment->set_source_table('role_assignments', array('contextid' => backup::VAR_CONTEXTID)); 00574 } 00575 00576 // Define id annotations 00577 $override->annotate_ids('role', 'roleid'); 00578 00579 $assignment->annotate_ids('role', 'roleid'); 00580 00581 $assignment->annotate_ids('user', 'userid'); 00582 00583 //TODO: how do we annotate the itemid? the meaning depends on the content of component table (skodak) 00584 00585 return $roles; 00586 } 00587 } 00588 00594 class backup_final_roles_structure_step extends backup_structure_step { 00595 00596 protected function define_structure() { 00597 00598 // Define elements 00599 00600 $rolesdef = new backup_nested_element('roles_definition'); 00601 00602 $role = new backup_nested_element('role', array('id'), array( 00603 'name', 'shortname', 'nameincourse', 'description', 00604 'sortorder', 'archetype')); 00605 00606 // Build the tree 00607 00608 $rolesdef->add_child($role); 00609 00610 // Define sources 00611 00612 $role->set_source_sql("SELECT r.*, rn.name AS nameincourse 00613 FROM {role} r 00614 JOIN {backup_ids_temp} bi ON r.id = bi.itemid 00615 LEFT JOIN {role_names} rn ON r.id = rn.roleid AND rn.contextid = ? 00616 WHERE bi.backupid = ? 00617 AND bi.itemname = 'rolefinal'", array(backup::VAR_CONTEXTID, backup::VAR_BACKUPID)); 00618 00619 // Return main element (rolesdef) 00620 return $rolesdef; 00621 } 00622 } 00623 00628 class backup_final_scales_structure_step extends backup_structure_step { 00629 00630 protected function define_structure() { 00631 00632 // Define elements 00633 00634 $scalesdef = new backup_nested_element('scales_definition'); 00635 00636 $scale = new backup_nested_element('scale', array('id'), array( 00637 'courseid', 'userid', 'name', 'scale', 00638 'description', 'descriptionformat', 'timemodified')); 00639 00640 // Build the tree 00641 00642 $scalesdef->add_child($scale); 00643 00644 // Define sources 00645 00646 $scale->set_source_sql("SELECT s.* 00647 FROM {scale} s 00648 JOIN {backup_ids_temp} bi ON s.id = bi.itemid 00649 WHERE bi.backupid = ? 00650 AND bi.itemname = 'scalefinal'", array(backup::VAR_BACKUPID)); 00651 00652 // Annotate scale files (they store files in system context, so pass it instead of default one) 00653 $scale->annotate_files('grade', 'scale', 'id', get_context_instance(CONTEXT_SYSTEM)->id); 00654 00655 // Return main element (scalesdef) 00656 return $scalesdef; 00657 } 00658 } 00659 00664 class backup_final_outcomes_structure_step extends backup_structure_step { 00665 00666 protected function define_structure() { 00667 00668 // Define elements 00669 00670 $outcomesdef = new backup_nested_element('outcomes_definition'); 00671 00672 $outcome = new backup_nested_element('outcome', array('id'), array( 00673 'courseid', 'userid', 'shortname', 'fullname', 00674 'scaleid', 'description', 'descriptionformat', 'timecreated', 00675 'timemodified','usermodified')); 00676 00677 // Build the tree 00678 00679 $outcomesdef->add_child($outcome); 00680 00681 // Define sources 00682 00683 $outcome->set_source_sql("SELECT o.* 00684 FROM {grade_outcomes} o 00685 JOIN {backup_ids_temp} bi ON o.id = bi.itemid 00686 WHERE bi.backupid = ? 00687 AND bi.itemname = 'outcomefinal'", array(backup::VAR_BACKUPID)); 00688 00689 // Annotate outcome files (they store files in system context, so pass it instead of default one) 00690 $outcome->annotate_files('grade', 'outcome', 'id', get_context_instance(CONTEXT_SYSTEM)->id); 00691 00692 // Return main element (outcomesdef) 00693 return $outcomesdef; 00694 } 00695 } 00696 00701 class backup_filters_structure_step extends backup_structure_step { 00702 00703 protected function define_structure() { 00704 00705 // Define each element separated 00706 00707 $filters = new backup_nested_element('filters'); 00708 00709 $actives = new backup_nested_element('filter_actives'); 00710 00711 $active = new backup_nested_element('filter_active', null, array('filter', 'active')); 00712 00713 $configs = new backup_nested_element('filter_configs'); 00714 00715 $config = new backup_nested_element('filter_config', null, array('filter', 'name', 'value')); 00716 00717 // Build the tree 00718 00719 $filters->add_child($actives); 00720 $filters->add_child($configs); 00721 00722 $actives->add_child($active); 00723 $configs->add_child($config); 00724 00725 // Define sources 00726 00727 list($activearr, $configarr) = filter_get_all_local_settings($this->task->get_contextid()); 00728 00729 $active->set_source_array($activearr); 00730 $config->set_source_array($configarr); 00731 00732 // Return the root element (filters) 00733 return $filters; 00734 } 00735 } 00736 00741 class backup_comments_structure_step extends backup_structure_step { 00742 00743 protected function define_structure() { 00744 00745 // Define each element separated 00746 00747 $comments = new backup_nested_element('comments'); 00748 00749 $comment = new backup_nested_element('comment', array('id'), array( 00750 'commentarea', 'itemid', 'content', 'format', 00751 'userid', 'timecreated')); 00752 00753 // Build the tree 00754 00755 $comments->add_child($comment); 00756 00757 // Define sources 00758 00759 $comment->set_source_table('comments', array('contextid' => backup::VAR_CONTEXTID)); 00760 00761 // Define id annotations 00762 00763 $comment->annotate_ids('user', 'userid'); 00764 00765 // Return the root element (comments) 00766 return $comments; 00767 } 00768 } 00769 00774 class backup_gradebook_structure_step extends backup_structure_step { 00775 00781 protected function execute_condition() { 00782 return backup_plan_dbops::require_gradebook_backup($this->get_courseid(), $this->get_backupid()); 00783 } 00784 00785 protected function define_structure() { 00786 00787 // are we including user info? 00788 $userinfo = $this->get_setting_value('users'); 00789 00790 $gradebook = new backup_nested_element('gradebook'); 00791 00792 //grade_letters are done in backup_activity_grades_structure_step() 00793 00794 //calculated grade items 00795 $grade_items = new backup_nested_element('grade_items'); 00796 $grade_item = new backup_nested_element('grade_item', array('id'), array( 00797 'categoryid', 'itemname', 'itemtype', 'itemmodule', 00798 'iteminstance', 'itemnumber', 'iteminfo', 'idnumber', 00799 'calculation', 'gradetype', 'grademax', 'grademin', 00800 'scaleid', 'outcomeid', 'gradepass', 'multfactor', 00801 'plusfactor', 'aggregationcoef', 'sortorder', 'display', 00802 'decimals', 'hidden', 'locked', 'locktime', 00803 'needsupdate', 'timecreated', 'timemodified')); 00804 00805 $grade_grades = new backup_nested_element('grade_grades'); 00806 $grade_grade = new backup_nested_element('grade_grade', array('id'), array( 00807 'userid', 'rawgrade', 'rawgrademax', 'rawgrademin', 00808 'rawscaleid', 'usermodified', 'finalgrade', 'hidden', 00809 'locked', 'locktime', 'exported', 'overridden', 00810 'excluded', 'feedback', 'feedbackformat', 'information', 00811 'informationformat', 'timecreated', 'timemodified')); 00812 00813 //grade_categories 00814 $grade_categories = new backup_nested_element('grade_categories'); 00815 $grade_category = new backup_nested_element('grade_category', array('id'), array( 00816 //'courseid', 00817 'parent', 'depth', 'path', 'fullname', 'aggregation', 'keephigh', 00818 'dropload', 'aggregateonlygraded', 'aggregateoutcomes', 'aggregatesubcats', 00819 'timecreated', 'timemodified', 'hidden')); 00820 00821 $letters = new backup_nested_element('grade_letters'); 00822 $letter = new backup_nested_element('grade_letter', 'id', array( 00823 'lowerboundary', 'letter')); 00824 00825 $grade_settings = new backup_nested_element('grade_settings'); 00826 $grade_setting = new backup_nested_element('grade_setting', 'id', array( 00827 'name', 'value')); 00828 00829 00830 // Build the tree 00831 $gradebook->add_child($grade_categories); 00832 $grade_categories->add_child($grade_category); 00833 00834 $gradebook->add_child($grade_items); 00835 $grade_items->add_child($grade_item); 00836 $grade_item->add_child($grade_grades); 00837 $grade_grades->add_child($grade_grade); 00838 00839 $gradebook->add_child($letters); 00840 $letters->add_child($letter); 00841 00842 $gradebook->add_child($grade_settings); 00843 $grade_settings->add_child($grade_setting); 00844 00845 // Define sources 00846 00847 //Include manual, category and the course grade item 00848 $grade_items_sql ="SELECT * FROM {grade_items} 00849 WHERE courseid = :courseid 00850 AND (itemtype='manual' OR itemtype='course' OR itemtype='category')"; 00851 $grade_items_params = array('courseid'=>backup::VAR_COURSEID); 00852 $grade_item->set_source_sql($grade_items_sql, $grade_items_params); 00853 00854 if ($userinfo) { 00855 $grade_grade->set_source_table('grade_grades', array('itemid' => backup::VAR_PARENTID)); 00856 } 00857 00858 $grade_category_sql = "SELECT gc.*, gi.sortorder 00859 FROM {grade_categories} gc 00860 JOIN {grade_items} gi ON (gi.iteminstance = gc.id) 00861 WHERE gc.courseid = :courseid 00862 AND (gi.itemtype='course' OR gi.itemtype='category') 00863 ORDER BY gc.parent ASC";//need parent categories before their children 00864 $grade_category_params = array('courseid'=>backup::VAR_COURSEID); 00865 $grade_category->set_source_sql($grade_category_sql, $grade_category_params); 00866 00867 $letter->set_source_table('grade_letters', array('contextid' => backup::VAR_CONTEXTID)); 00868 00869 $grade_setting->set_source_table('grade_settings', array('courseid' => backup::VAR_COURSEID)); 00870 00871 // Annotations (both as final as far as they are going to be exported in next steps) 00872 $grade_item->annotate_ids('scalefinal', 'scaleid'); // Straight as scalefinal because it's > 0 00873 $grade_item->annotate_ids('outcomefinal', 'outcomeid'); 00874 00875 //just in case there are any users not already annotated by the activities 00876 $grade_grade->annotate_ids('userfinal', 'userid'); 00877 00878 // Return the root element 00879 return $gradebook; 00880 } 00881 } 00882 00887 class backup_userscompletion_structure_step extends backup_structure_step { 00888 00889 protected function define_structure() { 00890 00891 // Define each element separated 00892 00893 $completions = new backup_nested_element('completions'); 00894 00895 $completion = new backup_nested_element('completion', array('id'), array( 00896 'userid', 'completionstate', 'viewed', 'timemodified')); 00897 00898 // Build the tree 00899 00900 $completions->add_child($completion); 00901 00902 // Define sources 00903 00904 $completion->set_source_table('course_modules_completion', array('coursemoduleid' => backup::VAR_MODID)); 00905 00906 // Define id annotations 00907 00908 $completion->annotate_ids('user', 'userid'); 00909 00910 // Return the root element (completions) 00911 return $completions; 00912 } 00913 } 00914 00919 class backup_groups_structure_step extends backup_structure_step { 00920 00921 protected function define_structure() { 00922 00923 // To know if we are including users 00924 $users = $this->get_setting_value('users'); 00925 00926 // Define each element separated 00927 00928 $groups = new backup_nested_element('groups'); 00929 00930 $group = new backup_nested_element('group', array('id'), array( 00931 'name', 'description', 'descriptionformat', 'enrolmentkey', 00932 'picture', 'hidepicture', 'timecreated', 'timemodified')); 00933 00934 $members = new backup_nested_element('group_members'); 00935 00936 $member = new backup_nested_element('group_member', array('id'), array( 00937 'userid', 'timeadded')); 00938 00939 $groupings = new backup_nested_element('groupings'); 00940 00941 $grouping = new backup_nested_element('grouping', 'id', array( 00942 'name', 'description', 'descriptionformat', 'configdata', 00943 'timecreated', 'timemodified')); 00944 00945 $groupinggroups = new backup_nested_element('grouping_groups'); 00946 00947 $groupinggroup = new backup_nested_element('grouping_group', array('id'), array( 00948 'groupid', 'timeadded')); 00949 00950 // Build the tree 00951 00952 $groups->add_child($group); 00953 $groups->add_child($groupings); 00954 00955 $group->add_child($members); 00956 $members->add_child($member); 00957 00958 $groupings->add_child($grouping); 00959 $grouping->add_child($groupinggroups); 00960 $groupinggroups->add_child($groupinggroup); 00961 00962 // Define sources 00963 00964 $group->set_source_sql(" 00965 SELECT g.* 00966 FROM {groups} g 00967 JOIN {backup_ids_temp} bi ON g.id = bi.itemid 00968 WHERE bi.backupid = ? 00969 AND bi.itemname = 'groupfinal'", array(backup::VAR_BACKUPID)); 00970 00971 // This only happens if we are including users 00972 if ($users) { 00973 $member->set_source_table('groups_members', array('groupid' => backup::VAR_PARENTID)); 00974 } 00975 00976 $grouping->set_source_sql(" 00977 SELECT g.* 00978 FROM {groupings} g 00979 JOIN {backup_ids_temp} bi ON g.id = bi.itemid 00980 WHERE bi.backupid = ? 00981 AND bi.itemname = 'groupingfinal'", array(backup::VAR_BACKUPID)); 00982 00983 $groupinggroup->set_source_table('groupings_groups', array('groupingid' => backup::VAR_PARENTID)); 00984 00985 // Define id annotations (as final) 00986 00987 $member->annotate_ids('userfinal', 'userid'); 00988 00989 // Define file annotations 00990 00991 $group->annotate_files('group', 'description', 'id'); 00992 $group->annotate_files('group', 'icon', 'id'); 00993 $grouping->annotate_files('grouping', 'description', 'id'); 00994 00995 // Return the root element (groups) 00996 return $groups; 00997 } 00998 } 00999 01005 class backup_users_structure_step extends backup_structure_step { 01006 01007 protected function define_structure() { 01008 global $CFG; 01009 01010 // To know if we are anonymizing users 01011 $anonymize = $this->get_setting_value('anonymize'); 01012 // To know if we are including role assignments 01013 $roleassignments = $this->get_setting_value('role_assignments'); 01014 01015 // Define each element separated 01016 01017 $users = new backup_nested_element('users'); 01018 01019 // Create the array of user fields by hand, as far as we have various bits to control 01020 // anonymize option, password backup, mnethostid... 01021 01022 // First, the fields not needing anonymization nor special handling 01023 $normalfields = array( 01024 'confirmed', 'policyagreed', 'deleted', 01025 'lang', 'theme', 'timezone', 'firstaccess', 01026 'lastaccess', 'lastlogin', 'currentlogin', 01027 'mailformat', 'maildigest', 'maildisplay', 'htmleditor', 01028 'ajax', 'autosubscribe', 'trackforums', 'timecreated', 01029 'timemodified', 'trustbitmask', 'screenreader'); 01030 01031 // Then, the fields potentially needing anonymization 01032 $anonfields = array( 01033 'username', 'idnumber', 'firstname', 'lastname', 01034 'email', 'icq', 'skype', 01035 'yahoo', 'aim', 'msn', 'phone1', 01036 'phone2', 'institution', 'department', 'address', 01037 'city', 'country', 'lastip', 'picture', 01038 'url', 'description', 'descriptionformat', 'imagealt', 'auth'); 01039 01040 // Add anonymized fields to $userfields with custom final element 01041 foreach ($anonfields as $field) { 01042 if ($anonymize) { 01043 $userfields[] = new anonymizer_final_element($field); 01044 } else { 01045 $userfields[] = $field; // No anonymization, normally added 01046 } 01047 } 01048 01049 // mnethosturl requires special handling (custom final element) 01050 $userfields[] = new mnethosturl_final_element('mnethosturl'); 01051 01052 // password added conditionally 01053 if (!empty($CFG->includeuserpasswordsinbackup)) { 01054 $userfields[] = 'password'; 01055 } 01056 01057 // Merge all the fields 01058 $userfields = array_merge($userfields, $normalfields); 01059 01060 $user = new backup_nested_element('user', array('id', 'contextid'), $userfields); 01061 01062 $customfields = new backup_nested_element('custom_fields'); 01063 01064 $customfield = new backup_nested_element('custom_field', array('id'), array( 01065 'field_name', 'field_type', 'field_data')); 01066 01067 $tags = new backup_nested_element('tags'); 01068 01069 $tag = new backup_nested_element('tag', array('id'), array( 01070 'name', 'rawname')); 01071 01072 $preferences = new backup_nested_element('preferences'); 01073 01074 $preference = new backup_nested_element('preference', array('id'), array( 01075 'name', 'value')); 01076 01077 $roles = new backup_nested_element('roles'); 01078 01079 $overrides = new backup_nested_element('role_overrides'); 01080 01081 $override = new backup_nested_element('override', array('id'), array( 01082 'roleid', 'capability', 'permission', 'timemodified', 01083 'modifierid')); 01084 01085 $assignments = new backup_nested_element('role_assignments'); 01086 01087 $assignment = new backup_nested_element('assignment', array('id'), array( 01088 'roleid', 'userid', 'timemodified', 'modifierid', 'component', //TODO: MDL-22793 add itemid here 01089 'sortorder')); 01090 01091 // Build the tree 01092 01093 $users->add_child($user); 01094 01095 $user->add_child($customfields); 01096 $customfields->add_child($customfield); 01097 01098 $user->add_child($tags); 01099 $tags->add_child($tag); 01100 01101 $user->add_child($preferences); 01102 $preferences->add_child($preference); 01103 01104 $user->add_child($roles); 01105 01106 $roles->add_child($overrides); 01107 $roles->add_child($assignments); 01108 01109 $overrides->add_child($override); 01110 $assignments->add_child($assignment); 01111 01112 // Define sources 01113 01114 $user->set_source_sql('SELECT u.*, c.id AS contextid, m.wwwroot AS mnethosturl 01115 FROM {user} u 01116 JOIN {backup_ids_temp} bi ON bi.itemid = u.id 01117 LEFT JOIN {context} c ON c.instanceid = u.id AND c.contextlevel = ' . CONTEXT_USER . ' 01118 LEFT JOIN {mnet_host} m ON m.id = u.mnethostid 01119 WHERE bi.backupid = ? 01120 AND bi.itemname = ?', array( 01121 backup_helper::is_sqlparam($this->get_backupid()), 01122 backup_helper::is_sqlparam('userfinal'))); 01123 01124 // All the rest on information is only added if we arent 01125 // in an anonymized backup 01126 if (!$anonymize) { 01127 $customfield->set_source_sql('SELECT f.id, f.shortname, f.datatype, d.data 01128 FROM {user_info_field} f 01129 JOIN {user_info_data} d ON d.fieldid = f.id 01130 WHERE d.userid = ?', array(backup::VAR_PARENTID)); 01131 01132 $customfield->set_source_alias('shortname', 'field_name'); 01133 $customfield->set_source_alias('datatype', 'field_type'); 01134 $customfield->set_source_alias('data', 'field_data'); 01135 01136 $tag->set_source_sql('SELECT t.id, t.name, t.rawname 01137 FROM {tag} t 01138 JOIN {tag_instance} ti ON ti.tagid = t.id 01139 WHERE ti.itemtype = ? 01140 AND ti.itemid = ?', array( 01141 backup_helper::is_sqlparam('user'), 01142 backup::VAR_PARENTID)); 01143 01144 $preference->set_source_table('user_preferences', array('userid' => backup::VAR_PARENTID)); 01145 01146 $override->set_source_table('role_capabilities', array('contextid' => '/users/user/contextid')); 01147 01148 // Assignments only added if specified 01149 if ($roleassignments) { 01150 $assignment->set_source_table('role_assignments', array('contextid' => '/users/user/contextid')); 01151 } 01152 01153 // Define id annotations (as final) 01154 $override->annotate_ids('rolefinal', 'roleid'); 01155 } 01156 01157 // Return root element (users) 01158 return $users; 01159 } 01160 } 01161 01167 class backup_block_instance_structure_step extends backup_structure_step { 01168 01169 protected function define_structure() { 01170 global $DB; 01171 01172 // Define each element separated 01173 01174 $block = new backup_nested_element('block', array('id', 'contextid', 'version'), array( 01175 'blockname', 'parentcontextid', 'showinsubcontexts', 'pagetypepattern', 01176 'subpagepattern', 'defaultregion', 'defaultweight', 'configdata')); 01177 01178 $positions = new backup_nested_element('block_positions'); 01179 01180 $position = new backup_nested_element('block_position', array('id'), array( 01181 'contextid', 'pagetype', 'subpage', 'visible', 01182 'region', 'weight')); 01183 01184 // Build the tree 01185 01186 $block->add_child($positions); 01187 $positions->add_child($position); 01188 01189 // Transform configdata information if needed (process links and friends) 01190 $blockrec = $DB->get_record('block_instances', array('id' => $this->task->get_blockid())); 01191 if ($attrstotransform = $this->task->get_configdata_encoded_attributes()) { 01192 $configdata = (array)unserialize(base64_decode($blockrec->configdata)); 01193 foreach ($configdata as $attribute => $value) { 01194 if (in_array($attribute, $attrstotransform)) { 01195 $configdata[$attribute] = $this->contenttransformer->process($value); 01196 } 01197 } 01198 $blockrec->configdata = base64_encode(serialize((object)$configdata)); 01199 } 01200 $blockrec->contextid = $this->task->get_contextid(); 01201 // Get the version of the block 01202 $blockrec->version = $DB->get_field('block', 'version', array('name' => $this->task->get_blockname())); 01203 01204 // Define sources 01205 01206 $block->set_source_array(array($blockrec)); 01207 01208 $position->set_source_table('block_positions', array('blockinstanceid' => backup::VAR_PARENTID)); 01209 01210 // File anotations (for fileareas specified on each block) 01211 foreach ($this->task->get_fileareas() as $filearea) { 01212 $block->annotate_files('block_' . $this->task->get_blockname(), $filearea, null); 01213 } 01214 01215 // Return the root element (block) 01216 return $block; 01217 } 01218 } 01219 01226 class backup_course_logs_structure_step extends backup_structure_step { 01227 01228 protected function define_structure() { 01229 01230 // Define each element separated 01231 01232 $logs = new backup_nested_element('logs'); 01233 01234 $log = new backup_nested_element('log', array('id'), array( 01235 'time', 'userid', 'ip', 'module', 01236 'action', 'url', 'info')); 01237 01238 // Build the tree 01239 01240 $logs->add_child($log); 01241 01242 // Define sources (all the records belonging to the course, having cmid = 0) 01243 01244 $log->set_source_table('log', array('course' => backup::VAR_COURSEID, 'cmid' => backup_helper::is_sqlparam(0))); 01245 01246 // Annotations 01247 // NOTE: We don't annotate users from logs as far as they MUST be 01248 // always annotated by the course (enrol, ras... whatever) 01249 01250 // Return the root element (logs) 01251 01252 return $logs; 01253 } 01254 } 01255 01260 class backup_activity_logs_structure_step extends backup_structure_step { 01261 01262 protected function define_structure() { 01263 01264 // Define each element separated 01265 01266 $logs = new backup_nested_element('logs'); 01267 01268 $log = new backup_nested_element('log', array('id'), array( 01269 'time', 'userid', 'ip', 'module', 01270 'action', 'url', 'info')); 01271 01272 // Build the tree 01273 01274 $logs->add_child($log); 01275 01276 // Define sources 01277 01278 $log->set_source_table('log', array('cmid' => backup::VAR_MODID)); 01279 01280 // Annotations 01281 // NOTE: We don't annotate users from logs as far as they MUST be 01282 // always annotated by the activity (true participants). 01283 01284 // Return the root element (logs) 01285 01286 return $logs; 01287 } 01288 } 01289 01294 class backup_inforef_structure_step extends backup_structure_step { 01295 01296 protected function define_structure() { 01297 01298 // Items we want to include in the inforef file. 01299 $items = backup_helper::get_inforef_itemnames(); 01300 01301 // Build the tree 01302 01303 $inforef = new backup_nested_element('inforef'); 01304 01305 // For each item, conditionally, if there are already records, build element 01306 foreach ($items as $itemname) { 01307 if (backup_structure_dbops::annotations_exist($this->get_backupid(), $itemname)) { 01308 $elementroot = new backup_nested_element($itemname . 'ref'); 01309 $element = new backup_nested_element($itemname, array(), array('id')); 01310 $inforef->add_child($elementroot); 01311 $elementroot->add_child($element); 01312 $element->set_source_sql(" 01313 SELECT itemid AS id 01314 FROM {backup_ids_temp} 01315 WHERE backupid = ? 01316 AND itemname = ?", 01317 array(backup::VAR_BACKUPID, backup_helper::is_sqlparam($itemname))); 01318 } 01319 } 01320 01321 // We don't annotate anything there, but rely in the next step 01322 // (move_inforef_annotations_to_final) that will change all the 01323 // already saved 'inforref' entries to their 'final' annotations. 01324 return $inforef; 01325 } 01326 } 01327 01332 class move_inforef_annotations_to_final extends backup_execution_step { 01333 01334 protected function define_execution() { 01335 01336 // Items we want to include in the inforef file 01337 $items = backup_helper::get_inforef_itemnames(); 01338 foreach ($items as $itemname) { 01339 // Delegate to dbops 01340 backup_structure_dbops::move_annotations_to_final($this->get_backupid(), $itemname); 01341 } 01342 } 01343 } 01344 01351 class backup_final_files_structure_step extends backup_structure_step { 01352 01353 protected function define_structure() { 01354 01355 // Define elements 01356 01357 $files = new backup_nested_element('files'); 01358 01359 $file = new file_nested_element('file', array('id'), array( 01360 'contenthash', 'contextid', 'component', 'filearea', 'itemid', 01361 'filepath', 'filename', 'userid', 'filesize', 01362 'mimetype', 'status', 'timecreated', 'timemodified', 01363 'source', 'author', 'license', 'sortorder')); 01364 01365 // Build the tree 01366 01367 $files->add_child($file); 01368 01369 // Define sources 01370 01371 $file->set_source_sql("SELECT f.* 01372 FROM {files} f 01373 JOIN {backup_ids_temp} bi ON f.id = bi.itemid 01374 WHERE bi.backupid = ? 01375 AND bi.itemname = 'filefinal'", array(backup::VAR_BACKUPID)); 01376 01377 return $files; 01378 } 01379 } 01380 01385 class backup_main_structure_step extends backup_structure_step { 01386 01387 protected function define_structure() { 01388 01389 global $CFG; 01390 01391 $info = array(); 01392 01393 $info['name'] = $this->get_setting_value('filename'); 01394 $info['moodle_version'] = $CFG->version; 01395 $info['moodle_release'] = $CFG->release; 01396 $info['backup_version'] = $CFG->backup_version; 01397 $info['backup_release'] = $CFG->backup_release; 01398 $info['backup_date'] = time(); 01399 $info['backup_uniqueid']= $this->get_backupid(); 01400 $info['mnet_remoteusers']=backup_controller_dbops::backup_includes_mnet_remote_users($this->get_backupid()); 01401 $info['original_wwwroot']=$CFG->wwwroot; 01402 $info['original_site_identifier_hash'] = md5(get_site_identifier()); 01403 $info['original_course_id'] = $this->get_courseid(); 01404 $originalcourseinfo = backup_controller_dbops::backup_get_original_course_info($this->get_courseid()); 01405 $info['original_course_fullname'] = $originalcourseinfo->fullname; 01406 $info['original_course_shortname'] = $originalcourseinfo->shortname; 01407 $info['original_course_startdate'] = $originalcourseinfo->startdate; 01408 $info['original_course_contextid'] = get_context_instance(CONTEXT_COURSE, $this->get_courseid())->id; 01409 $info['original_system_contextid'] = get_context_instance(CONTEXT_SYSTEM)->id; 01410 01411 // Get more information from controller 01412 list($dinfo, $cinfo, $sinfo) = backup_controller_dbops::get_moodle_backup_information($this->get_backupid()); 01413 01414 // Define elements 01415 01416 $moodle_backup = new backup_nested_element('moodle_backup'); 01417 01418 $information = new backup_nested_element('information', null, array( 01419 'name', 'moodle_version', 'moodle_release', 'backup_version', 01420 'backup_release', 'backup_date', 'mnet_remoteusers', 'original_wwwroot', 01421 'original_site_identifier_hash', 'original_course_id', 01422 'original_course_fullname', 'original_course_shortname', 'original_course_startdate', 01423 'original_course_contextid', 'original_system_contextid')); 01424 01425 $details = new backup_nested_element('details'); 01426 01427 $detail = new backup_nested_element('detail', array('backup_id'), array( 01428 'type', 'format', 'interactive', 'mode', 01429 'execution', 'executiontime')); 01430 01431 $contents = new backup_nested_element('contents'); 01432 01433 $activities = new backup_nested_element('activities'); 01434 01435 $activity = new backup_nested_element('activity', null, array( 01436 'moduleid', 'sectionid', 'modulename', 'title', 01437 'directory')); 01438 01439 $sections = new backup_nested_element('sections'); 01440 01441 $section = new backup_nested_element('section', null, array( 01442 'sectionid', 'title', 'directory')); 01443 01444 $course = new backup_nested_element('course', null, array( 01445 'courseid', 'title', 'directory')); 01446 01447 $settings = new backup_nested_element('settings'); 01448 01449 $setting = new backup_nested_element('setting', null, array( 01450 'level', 'section', 'activity', 'name', 'value')); 01451 01452 // Build the tree 01453 01454 $moodle_backup->add_child($information); 01455 01456 $information->add_child($details); 01457 $details->add_child($detail); 01458 01459 $information->add_child($contents); 01460 if (!empty($cinfo['activities'])) { 01461 $contents->add_child($activities); 01462 $activities->add_child($activity); 01463 } 01464 if (!empty($cinfo['sections'])) { 01465 $contents->add_child($sections); 01466 $sections->add_child($section); 01467 } 01468 if (!empty($cinfo['course'])) { 01469 $contents->add_child($course); 01470 } 01471 01472 $information->add_child($settings); 01473 $settings->add_child($setting); 01474 01475 01476 // Set the sources 01477 01478 $information->set_source_array(array((object)$info)); 01479 01480 $detail->set_source_array($dinfo); 01481 01482 $activity->set_source_array($cinfo['activities']); 01483 01484 $section->set_source_array($cinfo['sections']); 01485 01486 $course->set_source_array($cinfo['course']); 01487 01488 $setting->set_source_array($sinfo); 01489 01490 // Prepare some information to be sent to main moodle_backup.xml file 01491 return $moodle_backup; 01492 } 01493 01494 } 01495 01499 class backup_zip_contents extends backup_execution_step { 01500 01501 protected function define_execution() { 01502 01503 // Get basepath 01504 $basepath = $this->get_basepath(); 01505 01506 // Get the list of files in directory 01507 $filestemp = get_directory_list($basepath, '', false, true, true); 01508 $files = array(); 01509 foreach ($filestemp as $file) { // Add zip paths and fs paths to all them 01510 $files[$file] = $basepath . '/' . $file; 01511 } 01512 01513 // Add the log file if exists 01514 $logfilepath = $basepath . '.log'; 01515 if (file_exists($logfilepath)) { 01516 $files['moodle_backup.log'] = $logfilepath; 01517 } 01518 01519 // Calculate the zip fullpath (in OS temp area it's always backup.mbz) 01520 $zipfile = $basepath . '/backup.mbz'; 01521 01522 // Get the zip packer 01523 $zippacker = get_file_packer('application/zip'); 01524 01525 // Zip files 01526 $zippacker->archive_to_pathname($files, $zipfile); 01527 } 01528 } 01529 01533 class backup_store_backup_file extends backup_execution_step { 01534 01535 protected function define_execution() { 01536 01537 // Get basepath 01538 $basepath = $this->get_basepath(); 01539 01540 // Calculate the zip fullpath (in OS temp area it's always backup.mbz) 01541 $zipfile = $basepath . '/backup.mbz'; 01542 01543 // Perform storage and return it (TODO: shouldn't be array but proper result object) 01544 return array('backup_destination' => backup_helper::store_backup_file($this->get_backupid(), $zipfile)); 01545 } 01546 } 01547 01548 01553 class backup_activity_grade_items_to_ids extends backup_execution_step { 01554 01555 protected function define_execution() { 01556 01557 // Fetch all activity grade items 01558 if ($items = grade_item::fetch_all(array( 01559 'itemtype' => 'mod', 'itemmodule' => $this->task->get_modulename(), 01560 'iteminstance' => $this->task->get_activityid(), 'courseid' => $this->task->get_courseid()))) { 01561 // Annotate them in backup_ids 01562 foreach ($items as $item) { 01563 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'grade_item', $item->id); 01564 } 01565 } 01566 } 01567 } 01568 01572 class backup_annotate_course_groups_and_groupings extends backup_execution_step { 01573 01574 protected function define_execution() { 01575 global $DB; 01576 01577 // Get all the course groups 01578 if ($groups = $DB->get_records('groups', array( 01579 'courseid' => $this->task->get_courseid()))) { 01580 foreach ($groups as $group) { 01581 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'group', $group->id); 01582 } 01583 } 01584 01585 // Get all the course groupings 01586 if ($groupings = $DB->get_records('groupings', array( 01587 'courseid' => $this->task->get_courseid()))) { 01588 foreach ($groupings as $grouping) { 01589 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'grouping', $grouping->id); 01590 } 01591 } 01592 } 01593 } 01594 01598 class backup_annotate_groups_from_groupings extends backup_execution_step { 01599 01600 protected function define_execution() { 01601 global $DB; 01602 01603 // Fetch all the annotated groupings 01604 if ($groupings = $DB->get_records('backup_ids_temp', array( 01605 'backupid' => $this->get_backupid(), 'itemname' => 'grouping'))) { 01606 foreach ($groupings as $grouping) { 01607 if ($groups = $DB->get_records('groupings_groups', array( 01608 'groupingid' => $grouping->itemid))) { 01609 foreach ($groups as $group) { 01610 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'group', $group->groupid); 01611 } 01612 } 01613 } 01614 } 01615 } 01616 } 01617 01621 class backup_annotate_scales_from_outcomes extends backup_execution_step { 01622 01623 protected function define_execution() { 01624 global $DB; 01625 01626 // Fetch all the annotated outcomes 01627 if ($outcomes = $DB->get_records('backup_ids_temp', array( 01628 'backupid' => $this->get_backupid(), 'itemname' => 'outcome'))) { 01629 foreach ($outcomes as $outcome) { 01630 if ($scale = $DB->get_record('grade_outcomes', array( 01631 'id' => $outcome->itemid))) { 01632 // Annotate as scalefinal because it's > 0 01633 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'scalefinal', $scale->scaleid); 01634 } 01635 } 01636 } 01637 } 01638 } 01639 01648 class backup_annotate_all_question_files extends backup_execution_step { 01649 01650 protected function define_execution() { 01651 global $DB; 01652 01653 // Get all the different contexts for the final question_categories 01654 // annotated along the whole backup 01655 $rs = $DB->get_recordset_sql("SELECT DISTINCT qc.contextid 01656 FROM {question_categories} qc 01657 JOIN {backup_ids_temp} bi ON bi.itemid = qc.id 01658 WHERE bi.backupid = ? 01659 AND bi.itemname = 'question_categoryfinal'", array($this->get_backupid())); 01660 // To know about qtype specific components/fileareas 01661 $components = backup_qtype_plugin::get_components_and_fileareas(); 01662 // Let's loop 01663 foreach($rs as $record) { 01664 // We don't need to specify filearea nor itemid as far as by 01665 // component and context it's enough to annotate the whole bank files 01666 // This backups "questiontext", "generalfeedback" and "answerfeedback" fileareas (all them 01667 // belonging to the "question" component 01668 backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', null, null); 01669 // Again, it is enough to pick files only by context and component 01670 // Do it for qtype specific components 01671 foreach ($components as $component => $fileareas) { 01672 backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, $component, null, null); 01673 } 01674 } 01675 $rs->close(); 01676 } 01677 } 01678 01684 class backup_questions_structure_step extends backup_structure_step { 01685 01686 protected function define_structure() { 01687 01688 // Define each element separated 01689 01690 $qcategories = new backup_nested_element('question_categories'); 01691 01692 $qcategory = new backup_nested_element('question_category', array('id'), array( 01693 'name', 'contextid', 'contextlevel', 'contextinstanceid', 01694 'info', 'infoformat', 'stamp', 'parent', 01695 'sortorder')); 01696 01697 $questions = new backup_nested_element('questions'); 01698 01699 $question = new backup_nested_element('question', array('id'), array( 01700 'parent', 'name', 'questiontext', 'questiontextformat', 01701 'generalfeedback', 'generalfeedbackformat', 'defaultmark', 'penalty', 01702 'qtype', 'length', 'stamp', 'version', 01703 'hidden', 'timecreated', 'timemodified', 'createdby', 'modifiedby')); 01704 01705 // attach qtype plugin structure to $question element, only one allowed 01706 $this->add_plugin_structure('qtype', $question, false); 01707 01708 $qhints = new backup_nested_element('question_hints'); 01709 01710 $qhint = new backup_nested_element('question_hint', array('id'), array( 01711 'hint', 'hintformat', 'shownumcorrect', 'clearwrong', 'options')); 01712 01713 // Build the tree 01714 01715 $qcategories->add_child($qcategory); 01716 $qcategory->add_child($questions); 01717 $questions->add_child($question); 01718 $question->add_child($qhints); 01719 $qhints->add_child($qhint); 01720 01721 // Define the sources 01722 01723 $qcategory->set_source_sql(" 01724 SELECT gc.*, contextlevel, instanceid AS contextinstanceid 01725 FROM {question_categories} gc 01726 JOIN {backup_ids_temp} bi ON bi.itemid = gc.id 01727 JOIN {context} co ON co.id = gc.contextid 01728 WHERE bi.backupid = ? 01729 AND bi.itemname = 'question_categoryfinal'", array(backup::VAR_BACKUPID)); 01730 01731 $question->set_source_table('question', array('category' => backup::VAR_PARENTID)); 01732 01733 $qhint->set_source_sql(' 01734 SELECT * 01735 FROM {question_hints} 01736 WHERE questionid = :questionid 01737 ORDER BY id', 01738 array('questionid' => backup::VAR_PARENTID)); 01739 01740 // don't need to annotate ids nor files 01741 // (already done by {@link backup_annotate_all_question_files} 01742 01743 return $qcategories; 01744 } 01745 } 01746 01747 01748 01756 class backup_annotate_all_user_files extends backup_execution_step { 01757 01758 protected function define_execution() { 01759 global $DB; 01760 01761 // List of fileareas we are going to annotate 01762 $fileareas = array('profile', 'icon'); 01763 01764 if ($this->get_setting_value('user_files')) { // private files only if enabled in settings 01765 $fileareas[] = 'private'; 01766 } 01767 01768 // Fetch all annotated (final) users 01769 $rs = $DB->get_recordset('backup_ids_temp', array( 01770 'backupid' => $this->get_backupid(), 'itemname' => 'userfinal')); 01771 foreach ($rs as $record) { 01772 $userid = $record->itemid; 01773 $userctx = get_context_instance(CONTEXT_USER, $userid); 01774 if (!$userctx) { 01775 continue; // User has not context, sure it's a deleted user, so cannot have files 01776 } 01777 // Proceed with every user filearea 01778 foreach ($fileareas as $filearea) { 01779 // We don't need to specify itemid ($userid - 5th param) as far as by 01780 // context we can get all the associated files. See MDL-22092 01781 backup_structure_dbops::annotate_files($this->get_backupid(), $userctx->id, 'user', $filearea, null); 01782 } 01783 } 01784 $rs->close(); 01785 } 01786 } 01787 01788 01792 class backup_activity_grading_structure_step extends backup_structure_step { 01793 01797 protected function execute_condition() { 01798 return plugin_supports('mod', $this->get_task()->get_modulename(), FEATURE_ADVANCED_GRADING, false); 01799 } 01800 01804 protected function define_structure() { 01805 01806 // To know if we are including userinfo 01807 $userinfo = $this->get_setting_value('userinfo'); 01808 01809 // Define the elements 01810 01811 $areas = new backup_nested_element('areas'); 01812 01813 $area = new backup_nested_element('area', array('id'), array( 01814 'areaname', 'activemethod')); 01815 01816 $definitions = new backup_nested_element('definitions'); 01817 01818 $definition = new backup_nested_element('definition', array('id'), array( 01819 'method', 'name', 'description', 'descriptionformat', 'status', 01820 'timecreated', 'timemodified', 'options')); 01821 01822 $instances = new backup_nested_element('instances'); 01823 01824 $instance = new backup_nested_element('instance', array('id'), array( 01825 'raterid', 'itemid', 'rawgrade', 'status', 'feedback', 01826 'feedbackformat', 'timemodified')); 01827 01828 // Build the tree including the method specific structures 01829 // (beware - the order of how gradingform plugins structures are attached is important) 01830 $areas->add_child($area); 01831 $area->add_child($definitions); 01832 $definitions->add_child($definition); 01833 $this->add_plugin_structure('gradingform', $definition, true); 01834 $definition->add_child($instances); 01835 $instances->add_child($instance); 01836 $this->add_plugin_structure('gradingform', $instance, false); 01837 01838 // Define data sources 01839 01840 $area->set_source_table('grading_areas', array('contextid' => backup::VAR_CONTEXTID, 01841 'component' => array('sqlparam' => 'mod_'.$this->get_task()->get_modulename()))); 01842 01843 $definition->set_source_table('grading_definitions', array('areaid' => backup::VAR_PARENTID)); 01844 01845 if ($userinfo) { 01846 $instance->set_source_table('grading_instances', array('definitionid' => backup::VAR_PARENTID)); 01847 } 01848 01849 // Annotate references 01850 $definition->annotate_files('grading', 'description', 'id'); 01851 $instance->annotate_ids('user', 'raterid'); 01852 01853 // Return the root element 01854 return $areas; 01855 } 01856 } 01857 01858 01863 class backup_activity_grades_structure_step extends backup_structure_step { 01864 01865 protected function define_structure() { 01866 01867 // To know if we are including userinfo 01868 $userinfo = $this->get_setting_value('userinfo'); 01869 01870 // Define each element separated 01871 01872 $book = new backup_nested_element('activity_gradebook'); 01873 01874 $items = new backup_nested_element('grade_items'); 01875 01876 $item = new backup_nested_element('grade_item', array('id'), array( 01877 'categoryid', 'itemname', 'itemtype', 'itemmodule', 01878 'iteminstance', 'itemnumber', 'iteminfo', 'idnumber', 01879 'calculation', 'gradetype', 'grademax', 'grademin', 01880 'scaleid', 'outcomeid', 'gradepass', 'multfactor', 01881 'plusfactor', 'aggregationcoef', 'sortorder', 'display', 01882 'decimals', 'hidden', 'locked', 'locktime', 01883 'needsupdate', 'timecreated', 'timemodified')); 01884 01885 $grades = new backup_nested_element('grade_grades'); 01886 01887 $grade = new backup_nested_element('grade_grade', array('id'), array( 01888 'userid', 'rawgrade', 'rawgrademax', 'rawgrademin', 01889 'rawscaleid', 'usermodified', 'finalgrade', 'hidden', 01890 'locked', 'locktime', 'exported', 'overridden', 01891 'excluded', 'feedback', 'feedbackformat', 'information', 01892 'informationformat', 'timecreated', 'timemodified')); 01893 01894 $letters = new backup_nested_element('grade_letters'); 01895 01896 $letter = new backup_nested_element('grade_letter', 'id', array( 01897 'lowerboundary', 'letter')); 01898 01899 // Build the tree 01900 01901 $book->add_child($items); 01902 $items->add_child($item); 01903 01904 $item->add_child($grades); 01905 $grades->add_child($grade); 01906 01907 $book->add_child($letters); 01908 $letters->add_child($letter); 01909 01910 // Define sources 01911 01912 $item->set_source_sql("SELECT gi.* 01913 FROM {grade_items} gi 01914 JOIN {backup_ids_temp} bi ON gi.id = bi.itemid 01915 WHERE bi.backupid = ? 01916 AND bi.itemname = 'grade_item'", array(backup::VAR_BACKUPID)); 01917 01918 // This only happens if we are including user info 01919 if ($userinfo) { 01920 $grade->set_source_table('grade_grades', array('itemid' => backup::VAR_PARENTID)); 01921 } 01922 01923 $letter->set_source_table('grade_letters', array('contextid' => backup::VAR_CONTEXTID)); 01924 01925 // Annotations 01926 01927 $item->annotate_ids('scalefinal', 'scaleid'); // Straight as scalefinal because it's > 0 01928 $item->annotate_ids('outcome', 'outcomeid'); 01929 01930 $grade->annotate_ids('user', 'userid'); 01931 $grade->annotate_ids('user', 'usermodified'); 01932 01933 // Return the root element (book) 01934 01935 return $book; 01936 } 01937 } 01938 01942 class backup_course_completion_structure_step extends backup_structure_step { 01943 01944 protected function execute_condition() { 01945 // Check that all activities have been included 01946 if ($this->task->is_excluding_activities()) { 01947 return false; 01948 } 01949 return true; 01950 } 01951 01957 protected function define_structure() { 01958 01959 // To know if we are including user completion info 01960 $userinfo = $this->get_setting_value('userscompletion'); 01961 01962 $cc = new backup_nested_element('course_completion'); 01963 01964 $criteria = new backup_nested_element('course_completion_criteria', array('id'), array( 01965 'course','criteriatype', 'module', 'moduleinstance', 'courseinstanceshortname', 'enrolperiod', 'timeend', 'gradepass', 'role' 01966 )); 01967 01968 $criteriacompletions = new backup_nested_element('course_completion_crit_completions'); 01969 01970 $criteriacomplete = new backup_nested_element('course_completion_crit_compl', array('id'), array( 01971 'criteriaid', 'userid','gradefinal','unenrolled','deleted','timecompleted' 01972 )); 01973 01974 $coursecompletions = new backup_nested_element('course_completions', array('id'), array( 01975 'userid', 'course', 'deleted', 'timenotified', 'timeenrolled','timestarted','timecompleted','reaggregate' 01976 )); 01977 01978 $notify = new backup_nested_element('course_completion_notify', array('id'), array( 01979 'course','role','message','timesent' 01980 )); 01981 01982 $aggregatemethod = new backup_nested_element('course_completion_aggr_methd', array('id'), array( 01983 'course','criteriatype','method','value' 01984 )); 01985 01986 $cc->add_child($criteria); 01987 $criteria->add_child($criteriacompletions); 01988 $criteriacompletions->add_child($criteriacomplete); 01989 $cc->add_child($coursecompletions); 01990 $cc->add_child($notify); 01991 $cc->add_child($aggregatemethod); 01992 01993 // We need to get the courseinstances shortname rather than an ID for restore 01994 $criteria->set_source_sql("SELECT ccc.*, c.shortname AS courseinstanceshortname 01995 FROM {course_completion_criteria} ccc 01996 LEFT JOIN {course} c ON c.id = ccc.courseinstance 01997 WHERE ccc.course = ?", array(backup::VAR_COURSEID)); 01998 01999 02000 $notify->set_source_table('course_completion_notify', array('course' => backup::VAR_COURSEID)); 02001 $aggregatemethod->set_source_table('course_completion_aggr_methd', array('course' => backup::VAR_COURSEID)); 02002 02003 if ($userinfo) { 02004 $criteriacomplete->set_source_table('course_completion_crit_compl', array('criteriaid' => backup::VAR_PARENTID)); 02005 $coursecompletions->set_source_table('course_completions', array('course' => backup::VAR_COURSEID)); 02006 } 02007 02008 $criteria->annotate_ids('role', 'role'); 02009 $criteriacomplete->annotate_ids('user', 'userid'); 02010 $coursecompletions->annotate_ids('user', 'userid'); 02011 $notify->annotate_ids('role', 'role'); 02012 02013 return $cc; 02014 02015 } 02016 }