Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/backup/moodle2/backup_stepslib.php
Go to the documentation of this file.
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 }
 All Data Structures Namespaces Files Functions Variables Enumerations