3 // This file is part of Moodle - http://moodle.org/
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
20 * @subpackage backup-moodle2
21 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 * Define all the backup steps that will be used by common tasks in backup
28 class create_and_clean_temp_stuff extends backup_execution_step {
30 protected function define_execution() {
31 backup_helper::check_and_create_backup_dir($this->get_backupid());// Create backup temp dir
32 backup_helper::clear_backup_dir($this->get_backupid()); // Empty temp dir, just in case
33 backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60)); // Delete > 4 hours temp dirs
34 backup_controller_dbops::create_backup_ids_temp_table($this->get_backupid()); // Create ids temp table
39 * Create the directory where all the task (activity/block...) information will be stored
41 class create_taskbasepath_directory extends backup_execution_step {
43 protected function define_execution() {
45 $basepath = $this->task->get_taskbasepath();
46 if (!check_dir_exists($basepath, true, true)) {
47 throw new backup_step_exception('cannot_create_taskbasepath_directory', $basepath);
53 * Abtract tructure step, parent of all the activity structure steps. Used to wrap the
54 * activity structure definition within the main <activity ...> tag
56 abstract class backup_activity_structure_step extends backup_structure_step {
58 protected function prepare_activity_structure($activitystructure) {
60 // Create the wrap element
61 $activity = new backup_nested_element('activity', array('id', 'moduleid', 'modulename', 'contextid'), null);
64 $activity->add_child($activitystructure);
67 $activityarr = array((object)array(
68 'id' => $this->task->get_activityid(),
69 'moduleid' => $this->task->get_moduleid(),
70 'modulename' => $this->task->get_modulename(),
71 'contextid' => $this->task->get_contextid()));
73 $activity->set_source_array($activityarr);
75 // Return the root element (activity)
81 * Abtract structure step, parent of all the block structure steps. Used to wrap the
82 * block structure definition within the main <block ...> tag
84 abstract class backup_block_structure_step extends backup_structure_step {
86 protected function prepare_block_structure($blockstructure) {
88 // Create the wrap element
89 $block = new backup_nested_element('block', array('id', 'blockname', 'contextid'), null);
92 $block->add_child($blockstructure);
95 $blockarr = array((object)array(
96 'id' => $this->task->get_blockid(),
97 'blockname' => $this->task->get_blockname(),
98 'contextid' => $this->task->get_contextid()));
100 $block->set_source_array($blockarr);
102 // Return the root element (block)
108 * structure step that will generate the module.xml file for the activity,
109 * acummulating various information about the activity, annotating groupings
110 * and completion/avail conf
112 class backup_module_structure_step extends backup_structure_step {
114 protected function define_structure() {
116 // Define each element separated
118 $module = new backup_nested_element('module', array('id', 'version'), array(
119 'modulename', 'sectionid', 'sectionnumber', 'idnumber',
120 'added', 'score', 'indent', 'visible',
121 'visibleold', 'groupmode', 'groupingid', 'groupmembersonly',
122 'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected',
123 'availablefrom', 'availableuntil', 'showavailability'));
125 $availinfo = new backup_nested_element('availability_info');
126 $availability = new backup_nested_element('availability', array('id'), array(
127 'sourcecmid', 'requiredcompletion', 'gradeitemid', 'grademin', 'grademax'));
130 $module->add_child($availinfo);
131 $availinfo->add_child($availability);
135 $module->set_source_sql('
136 SELECT cm.*, m.version, m.name AS modulename, s.id AS sectionid, s.section AS sectionnumber
137 FROM {course_modules} cm
138 JOIN {modules} m ON m.id = cm.module
139 JOIN {course_sections} s ON s.id = cm.section
140 WHERE cm.id = ?', array(backup::VAR_MODID));
142 $availability->set_source_table('course_modules_availability', array('coursemoduleid' => backup::VAR_MODID));
144 // Define annotations
145 $module->annotate_ids('grouping', 'groupingid');
147 // Return the root element ($module)
153 * structure step that will genereate the section.xml file for the section
156 class backup_section_structure_step extends backup_structure_step {
158 protected function define_structure() {
160 // Define each element separated
162 $section = new backup_nested_element('section', array('id'), array(
163 'number', 'name', 'summary', 'sequence', 'visible'));
167 $section->set_source_table('course_sections', array('id' => backup::VAR_SECTIONID));
170 $section->set_source_alias('section', 'number');
173 $section->annotate_files(array('course_section'), 'id');
180 * structure step that will generate the course.xml file for the course, including
181 * course category reference, tags, metacourse, modules restriction information
182 * and some annotations (files & groupings)
184 class backup_course_structure_step extends backup_structure_step {
186 protected function define_structure() {
189 // Define each element separated
191 $course = new backup_nested_element('course', array('id', 'contextid'), array(
192 'shortname', 'fullname', 'idnumber', 'password',
193 'summary', 'summaryformat', 'format', 'showgrades',
194 'newsitems', 'guest', 'startdate', 'enrolperiod',
195 'numsections', 'marker', 'maxbytes', 'showreports',
196 'visible', 'hiddensections', 'groupmode', 'groupmodeforce',
197 'defaultgroupingid', 'lang', 'theme', 'cost',
198 'currency', 'timecreated', 'timemodified', 'metacourse',
199 'requested', 'restrictmodules', 'expirynotify', 'expirythreshold',
200 'notifystudents', 'enrollable', 'enrolstartdate', 'enrolenddate',
201 'enrol', 'defaultrole', 'enablecompletion'));
203 $category = new backup_nested_element('category', array('id'), array(
204 'name', 'description'));
206 $tags = new backup_nested_element('tags');
208 $tag = new backup_nested_element('tag', array('id'), array(
211 $allowedmodules = new backup_nested_element('allowed_modules');
213 $module = new backup_nested_element('module', array('modulename'));
217 $course->add_child($category);
219 $course->add_child($tags);
220 $tags->add_child($tag);
222 $course->add_child($allowedmodules);
223 $allowedmodules->add_child($module);
227 $courserec = $DB->get_record('course', array('id' => $this->task->get_courseid()));
228 $courserec->contextid = $this->task->get_contextid();
230 $course->set_source_array(array($courserec));
232 $categoryrec = $DB->get_record('course_categories', array('id' => $courserec->category));
234 $category->set_source_array(array($categoryrec));
236 $tag->set_source_sql('SELECT t.id, t.name, t.rawname
238 JOIN {tag_instance} ti ON ti.tagid = t.id
239 WHERE ti.itemtype = ?
240 AND ti.itemid = ?', array(
241 $this->is_sqlparam('course'),
242 backup::VAR_PARENTID));
244 $module->set_source_sql('SELECT m.name AS modulename
246 JOIN {course_allowed_modules} cam ON m.id = cam.module
247 WHERE course = ?', array(backup::VAR_COURSEID));
251 $course->annotate_ids('role', 'defaultrole');
252 $course->annotate_ids('grouping', 'defaultgroupingid');
254 $course->annotate_files(array('course_summary', 'course_content'), null);
256 // Return root element ($course)
263 * structure step that will generate the roles.xml file for the given context, observing
264 * the role_assignments setting to know if that part needs to be included
266 class backup_roles_structure_step extends backup_structure_step {
268 protected function define_structure() {
270 // To know if we are including role assignments
271 $roleassignments = $this->get_setting_value('role_assignments');
273 // Define each element separated
275 $roles = new backup_nested_element('roles');
277 $overrides = new backup_nested_element('role_overrides');
279 $override = new backup_nested_element('override', array('id'), array(
280 'roleid', 'capability', 'permission', 'timemodified',
283 $assignments = new backup_nested_element('role_assignments');
285 $assignment = new backup_nested_element('assignment', array('id'), array(
286 'roleid', 'userid', 'hidden', 'timestart',
287 'timeend', 'timemodified', 'modifierid', 'enrol',
291 $roles->add_child($overrides);
292 $roles->add_child($assignments);
294 $overrides->add_child($override);
295 $assignments->add_child($assignment);
299 $override->set_source_table('role_capabilities', array('contextid' => backup::VAR_CONTEXTID));
301 // Assignments only added if specified
302 if ($roleassignments) {
303 $assignment->set_source_table('role_assignments', array('contextid' => backup::VAR_CONTEXTID));
306 // Define id annotations
307 $override->annotate_ids('role', 'roleid');
309 $assignment->annotate_ids('role', 'roleid');
311 $assignment->annotate_ids('user', 'userid');
318 * structure step that will generate the roles.xml containing the
319 * list of roles used along the whole backup process. Just raw
320 * list of used roles from role table
322 class backup_final_roles_structure_step extends backup_structure_step {
324 protected function define_structure() {
328 $rolesdef = new backup_nested_element('roles_definition');
330 $role = new backup_nested_element('role', array('id'), array(
331 'name', 'shortname', 'nameincourse', 'description',
332 'sortorder', 'archetype'));
336 $rolesdef->add_child($role);
340 $role->set_source_sql("SELECT r.*, rn.name AS nameincourse
342 JOIN {backup_ids_temp} bi ON r.id = bi.itemid
343 LEFT JOIN {role_names} rn ON r.id = rn.roleid AND rn.contextid = ?
344 WHERE bi.backupid = ?
345 AND bi.itemname = 'rolefinal'", array(backup::VAR_CONTEXTID, backup::VAR_BACKUPID));
347 // Return main element (rolesdef)
353 * structure step that will generate the scales.xml containing the
354 * list of scales used along the whole backup process.
356 class backup_final_scales_structure_step extends backup_structure_step {
358 protected function define_structure() {
362 $scalesdef = new backup_nested_element('scales_definition');
364 $scale = new backup_nested_element('scale', array('id'), array(
365 'courseid', 'userid', 'name', 'scale',
366 'description', 'descriptionformat', 'timemodified'));
370 $scalesdef->add_child($scale);
374 $scale->set_source_sql("SELECT s.*
376 JOIN {backup_ids_temp} bi ON s.id = bi.itemid
377 WHERE bi.backupid = ?
378 AND bi.itemname = 'scalefinal'", array(backup::VAR_BACKUPID));
380 // Return main element (scalesdef)
386 * structure step that will generate the outcomes.xml containing the
387 * list of outcomes used along the whole backup process.
389 class backup_final_outcomes_structure_step extends backup_structure_step {
391 protected function define_structure() {
395 $outcomesdef = new backup_nested_element('outcomes_definition');
397 $outcome = new backup_nested_element('outcome', array('id'), array(
398 'courseid', 'userid', 'shortname', 'fullname',
399 'scaleid', 'description', 'descriptionformat', 'timecreated',
400 'timemodified','usermodified'));
404 $outcomesdef->add_child($outcome);
408 $outcome->set_source_sql("SELECT o.*
409 FROM {grade_outcomes} o
410 JOIN {backup_ids_temp} bi ON o.id = bi.itemid
411 WHERE bi.backupid = ?
412 AND bi.itemname = 'outcomefinal'", array(backup::VAR_BACKUPID));
414 // Return main element (outcomesdef)
420 * structure step in charge of constructing the filters.xml file for all the filters found
423 class backup_filters_structure_step extends backup_structure_step {
425 protected function define_structure() {
427 // Define each element separated
429 $filters = new backup_nested_element('filters');
431 $actives = new backup_nested_element('filter_actives');
433 $active = new backup_nested_element('filter_active', null, array('filter', 'active'));
435 $configs = new backup_nested_element('filter_configs');
437 $config = new backup_nested_element('filter_config', null, array('filter', 'name', 'value'));
441 $filters->add_child($actives);
442 $filters->add_child($configs);
444 $actives->add_child($active);
445 $configs->add_child($config);
449 list($activearr, $configarr) = filter_get_all_local_settings($this->task->get_contextid());
451 $active->set_source_array($activearr);
452 $config->set_source_array($configarr);
454 // Return the root element (filters)
460 * structure step in charge of constructing the comments.xml file for all the comments found
463 class backup_comments_structure_step extends backup_structure_step {
465 protected function define_structure() {
467 // Define each element separated
469 $comments = new backup_nested_element('comments');
471 $comment = new backup_nested_element('comment', array('id'), array(
472 'commentarea', 'itemid', 'content', 'format',
473 'userid', 'timecreated'));
477 $comments->add_child($comment);
481 $comment->set_source_table('comments', array('contextid' => backup::VAR_CONTEXTID));
483 // Define id annotations
485 $comment->annotate_ids('user', 'userid');
487 // Return the root element (comments)
493 * structure step in charge if constructing the completion.xml file for all the users completion
494 * information in a given activity
496 class backup_userscompletion_structure_step extends backup_structure_step {
498 protected function define_structure() {
500 // Define each element separated
502 $completions = new backup_nested_element('completions');
504 $completion = new backup_nested_element('completion', array('id'), array(
505 'userid', 'completionstate', 'viewed', 'timemodified'));
509 $completions->add_child($completion);
513 $completion->set_source_table('course_modules_completion', array('coursemoduleid' => backup::VAR_MODID));
515 // Define id annotations
517 $completion->annotate_ids('user', 'userid');
519 // Return the root element (completions)
525 * structure step in charge of constructing the main groups.xml file for all the groups and
526 * groupings information already annotated
528 class backup_groups_structure_step extends backup_structure_step {
530 protected function define_structure() {
532 // To know if we are including users
533 $users = $this->get_setting_value('users');
535 // Define each element separated
537 $groups = new backup_nested_element('groups');
539 $group = new backup_nested_element('group', array('id'), array(
540 'name', 'description', 'descriptionformat', 'enrolmentkey',
541 'picture', 'hidepicture', 'timecreated', 'timemodified'));
543 $members = new backup_nested_element('group_members');
545 $member = new backup_nested_element('group_member', array('id'), array(
546 'userid', 'timeadded'));
548 $groupings = new backup_nested_element('groupings');
550 $grouping = new backup_nested_element('grouping', 'id', array(
551 'name', 'description', 'descriptionformat', 'configdata',
552 'timecreated', 'timemodified'));
554 $groupinggroups = new backup_nested_element('grouping_groups');
556 $groupinggroup = new backup_nested_element('grouping_group', array('id'), array(
557 'groupid', 'timeadded'));
561 $groups->add_child($group);
562 $groups->add_child($groupings);
564 $group->add_child($members);
565 $members->add_child($member);
567 $groupings->add_child($grouping);
568 $grouping->add_child($groupinggroups);
569 $groupinggroups->add_child($groupinggroup);
573 $group->set_source_sql("
576 JOIN {backup_ids_temp} bi ON g.id = bi.itemid
577 WHERE bi.backupid = ?
578 AND bi.itemname = 'groupfinal'", array(backup::VAR_BACKUPID));
580 // This only happens if we are including users
582 $member->set_source_table('groups_members', array('groupid' => backup::VAR_PARENTID));
585 $grouping->set_source_sql("
588 JOIN {backup_ids_temp} bi ON g.id = bi.itemid
589 WHERE bi.backupid = ?
590 AND bi.itemname = 'groupingfinal'", array(backup::VAR_BACKUPID));
592 $groupinggroup->set_source_table('groupings_groups', array('groupingid' => backup::VAR_PARENTID));
594 // Define id annotations (as final)
596 $member->annotate_ids('userfinal', 'userid');
598 // Define file annotations
600 // TODO: Change "course_group_image" file area to the one finally used for group images
601 $group->annotate_files(array('course_group_description', 'course_group_image'), 'id');
603 // Return the root element (groups)
609 * structure step in charge of constructing the main users.xml file for all the users already
610 * annotated (final). Includes custom profile fields, preferences, tags, role assignments and
613 class backup_users_structure_step extends backup_structure_step {
615 protected function define_structure() {
618 // To know if we are anonymizing users
619 $anonymize = $this->get_setting_value('anonymize');
620 // To know if we are including role assignments
621 $roleassignments = $this->get_setting_value('role_assignments');
623 // Define each element separated
625 $users = new backup_nested_element('users');
627 // Create the array of user fields by hand, as far as we have various bits to control
628 // anonymize option, password backup, mnethostid...
630 // First, the fields not needing anonymization nor special handling
631 $normalfields = array(
632 'confirmed', 'policyagreed', 'deleted',
633 'lang', 'theme', 'timezone', 'firstaccess',
634 'lastaccess', 'lastlogin', 'currentlogin', 'secret',
635 'mailformat', 'maildigest', 'maildisplay', 'htmleditor',
636 'ajax', 'autosubscribe', 'trackforums', 'timecreated',
637 'timemodified', 'trustbitmask', 'screenreader');
639 // Then, the fields potentially needing anonymization
641 'username', 'idnumber', 'firstname', 'lastname',
642 'email', 'emailstop', 'lastip', 'picture',
643 'url', 'description', 'description_format', 'imagealt', 'auth');
645 // Add anonymized fields to $userfields with custom final element
646 foreach ($anonfields as $field) {
648 $userfields[] = new anonymizer_final_element($field);
650 $userfields[] = $field; // No anonymization, normally added
654 // mnethosturl requires special handling (custom final element)
655 $userfields[] = new mnethosturl_final_element('mnethosturl');
657 // password added conditionally
658 if (!empty($CFG->includeuserpasswordsinbackup)) {
659 $userfields[] = 'password';
662 // Merge all the fields
663 $userfields = array_merge($userfields, $normalfields);
665 $user = new backup_nested_element('user', array('id', 'contextid'), $userfields);
667 $customfields = new backup_nested_element('custom_fields');
669 $customfield = new backup_nested_element('custom_field', array('id'), array(
670 'field_name', 'field_type', 'field_data'));
672 $tags = new backup_nested_element('tags');
674 $tag = new backup_nested_element('tag', array('id'), array(
677 $preferences = new backup_nested_element('preferences');
679 $preference = new backup_nested_element('preference', array('id'), array(
682 $roles = new backup_nested_element('roles');
684 $overrides = new backup_nested_element('role_overrides');
686 $override = new backup_nested_element('override', array('id'), array(
687 'roleid', 'capability', 'permission', 'timemodified',
690 $assignments = new backup_nested_element('role_assignments');
692 $assignment = new backup_nested_element('assignment', array('id'), array(
693 'roleid', 'userid', 'hidden', 'timestart',
694 'timeend', 'timemodified', 'modifierid', 'enrol',
699 $users->add_child($user);
701 $user->add_child($customfields);
702 $customfields->add_child($customfield);
704 $user->add_child($tags);
705 $tags->add_child($tag);
707 $user->add_child($preferences);
708 $preferences->add_child($preference);
710 $user->add_child($roles);
712 $roles->add_child($overrides);
713 $roles->add_child($assignments);
715 $overrides->add_child($override);
716 $assignments->add_child($assignment);
720 $user->set_source_sql('SELECT u.*, c.id AS contextid, m.wwwroot AS mnethosturl
722 JOIN {backup_ids_temp} bi ON bi.itemid = u.id
723 JOIN {context} c ON c.instanceid = u.id
724 LEFT JOIN {mnet_host} m ON m.id = u.mnethostid
725 WHERE bi.backupid = ?
727 AND c.contextlevel = ?', array(
728 $this->is_sqlparam($this->get_backupid()),
729 $this->is_sqlparam('userfinal'),
730 $this->is_sqlparam(CONTEXT_USER)));
732 // All the rest on information is only added if we arent
733 // in an anonymized backup
735 $customfield->set_source_sql('SELECT f.id, f.shortname, f.datatype, d.data
736 FROM {user_info_field} f
737 JOIN {user_info_data} d ON d.fieldid = f.id
738 WHERE d.userid = ?', array(backup::VAR_PARENTID));
740 $customfield->set_source_alias('shortname', 'field_name');
741 $customfield->set_source_alias('datatype', 'field_type');
742 $customfield->set_source_alias('data', 'field_data');
744 $tag->set_source_sql('SELECT t.id, t.name, t.rawname
746 JOIN {tag_instance} ti ON ti.tagid = t.id
747 WHERE ti.itemtype = ?
748 AND ti.itemid = ?', array(
749 $this->is_sqlparam('user'),
750 backup::VAR_PARENTID));
752 $preference->set_source_table('user_preferences', array('userid' => backup::VAR_PARENTID));
754 $override->set_source_table('role_capabilities', array('contextid' => '/users/user/contextid'));
756 // Assignments only added if specified
757 if ($roleassignments) {
758 $assignment->set_source_table('role_assignments', array('contextid' => '/users/user/contextid'));
761 // Define id annotations (as final)
762 $override->annotate_ids('rolefinal', 'roleid');
765 // Return root element (users)
771 * structure step in charge of constructing the block.xml file for one
772 * given block (intance and positions). If the block has custom DB structure
773 * that will go to a separate file (different step defined in block class)
775 class backup_block_instance_structure_step extends backup_structure_step {
777 protected function define_structure() {
780 // Define each element separated
782 $block = new backup_nested_element('block', array('id', 'version'), array(
783 'blockname', 'showinsubcontexts', 'pagetypepattern', 'subpagepattern',
784 'defaultregion', 'defaultweight', 'configdata'));
786 $positions = new backup_nested_element('block_positions', null, array(
787 'contextid', 'pagetype', 'subpage', 'visible',
788 'region', 'weight'));
792 $block->add_child($positions);
794 // Transform configdata information if needed (process links and friends)
795 $blockrec = $DB->get_record('block_instances', array('id' => $this->task->get_blockid()));
796 if ($attrstotransform = $this->task->get_configdata_encoded_attributes()) {
797 $configdata = (array)unserialize(base64_decode($blockrec->configdata));
798 foreach ($configdata as $attribute => $value) {
799 if (in_array($attribute, $attrstotransform)) {
800 $configdata[$attribute] = $this->contenttransformer->process($value);
803 $blockrec->configdata = base64_encode(serialize((object)$configdata));
805 // Get the version of the block
806 $blockrec->version = $DB->get_field('block', 'version', array('name' => $this->task->get_blockname()));
810 $block->set_source_array(array($blockrec));
812 $positions->set_source_table('block_positions', array('blockinstanceid' => backup::VAR_PARENTID));
814 // Return the root element (block)
820 * structure step in charge of constructing the logs.xml file for all the log records found
823 class backup_activity_logs_structure_step extends backup_structure_step {
825 protected function define_structure() {
827 // Define each element separated
829 $logs = new backup_nested_element('logs');
831 $log = new backup_nested_element('log', array('id'), array(
832 'time', 'userid', 'ip', 'module',
833 'action', 'url', 'info'));
837 $logs->add_child($log);
841 $log->set_source_table('log', array('cmid' => backup::VAR_MODID));
844 // NOTE: We don't annotate users from logs as far as they MUST be
845 // always annotated by the activity.
847 // Return the root element (logs)
854 * structure in charge of constructing the inforef.xml file for all the items we want
855 * to have referenced there (users, roles, files...)
857 class backup_inforef_structure_step extends backup_structure_step {
859 protected function define_structure() {
861 // Items we want to include in the inforef file. NOTE: Important to keep this
862 // list 100% sync with the one in next step! Until we get better place for it (backup:CONST)
863 $items = array('user', 'grouping', 'group', 'role', 'file', 'scale', 'outcome', 'grade_item');
867 $inforef = new backup_nested_element('inforef');
869 // For each item, conditionally, if there are already records, build element
870 foreach ($items as $itemname) {
871 if (backup_structure_dbops::annotations_exist($this->get_backupid(), $itemname)) {
872 $elementroot = new backup_nested_element($itemname . 'ref');
873 $element = new backup_nested_element($itemname, array('id'));
874 $inforef->add_child($elementroot);
875 $elementroot->add_child($element);
876 $element->set_source_sql("
878 FROM {backup_ids_temp}
881 array(backup::VAR_BACKUPID, $this->is_sqlparam($itemname)));
885 // We don't annotate anything there, but rely in the next step
886 // (move_inforef_annotations_to_final) that will change all the
887 // already saved 'inforref' entries to their 'final' annotations.
893 * This step will get all the annotations already processed to inforef.xml file and
894 * transform them into 'final' annotations.
896 class move_inforef_annotations_to_final extends backup_execution_step {
898 protected function define_execution() {
900 // Items we want to include in the inforef file. NOTE: Important to keep this
901 // list 100% sync with the one in prev step! Until we get better place for it (backup:CONST)
902 $items = array('user', 'grouping', 'group', 'role', 'file', 'scale', 'outcome', 'grade_item');
903 foreach ($items as $itemname) {
905 backup_structure_dbops::move_annotations_to_final($this->get_backupid(), $itemname);
911 * structure in charge of constructing the files.xml file with all the
912 * annotated (final) files along the process. At, the same time, and
913 * using one specialised nested_element, will copy them form moodle storage
916 class backup_final_files_structure_step extends backup_structure_step {
918 protected function define_structure() {
922 $files = new backup_nested_element('files');
924 $file = new file_nested_element('file', array('id'), array(
925 'contenthash', 'contextid', 'filearea', 'itemid',
926 'filepath', 'filename', 'userid', 'filesize',
927 'mimetype', 'status', 'timecreated', 'timemodified',
928 'source', 'author', 'license'));
932 $files->add_child($file);
936 $file->set_source_sql("SELECT f.*
938 JOIN {backup_ids_temp} bi ON f.id = bi.itemid
939 WHERE bi.backupid = ?
940 AND bi.itemname = 'filefinal'", array(backup::VAR_BACKUPID));
947 * Structure step in charge of creating the main moodle_backup.xml file
948 * where all the information related to the backup, settings, license and
949 * other information needed on restore is added*/
950 class backup_main_structure_step extends backup_structure_step {
952 protected function define_structure() {
958 $info['name'] = $this->get_setting_value('filename');
959 $info['moodle_version'] = $CFG->version;
960 $info['moodle_release'] = $CFG->release;
961 $info['backup_version'] = $CFG->backup_version;
962 $info['backup_release'] = $CFG->backup_release;
963 $info['backup_date'] = time();
964 $info['backup_uniqueid']= $this->get_backupid();
965 $info['original_wwwroot']=$CFG->wwwroot;
966 $info['original_site_identifier'] = get_site_identifier();
967 $info['original_course_id'] = $this->get_courseid();
969 // Get more information from controller
970 list($dinfo, $cinfo, $sinfo) = backup_controller_dbops::get_moodle_backup_information($this->get_backupid());
974 $moodle_backup = new backup_nested_element('moodle_backup');
976 $information = new backup_nested_element('information', null, array(
977 'name', 'moodle_version', 'moodle_release', 'backup_version',
978 'backup_release', 'backup_date', 'original_wwwroot',
979 'original_site_identifier', 'original_course_id'));
981 $details = new backup_nested_element('details');
983 $detail = new backup_nested_element('detail', array('backup_id'), array(
984 'type', 'format', 'interactive', 'mode',
985 'execution', 'executiontime'));
987 $contents = new backup_nested_element('contents');
989 $activities = new backup_nested_element('activities');
991 $activity = new backup_nested_element('activity', null, array(
992 'moduleid', 'sectionid', 'modulename', 'title',
995 $sections = new backup_nested_element('sections');
997 $section = new backup_nested_element('section', null, array(
998 'sectionid', 'title', 'directory'));
1000 $course = new backup_nested_element('course', null, array(
1001 'courseid', 'title', 'directory'));
1003 $settings = new backup_nested_element('settings');
1005 $setting = new backup_nested_element('setting', null, array(
1006 'level', 'activity', 'name', 'value'));
1010 $moodle_backup->add_child($information);
1012 $information->add_child($details);
1013 $details->add_child($detail);
1015 $information->add_child($contents);
1016 if (!empty($cinfo['activities'])) {
1017 $contents->add_child($activities);
1018 $activities->add_child($activity);
1020 if (!empty($cinfo['sections'])) {
1021 $contents->add_child($sections);
1022 $sections->add_child($section);
1024 if (!empty($cinfo['course'])) {
1025 $contents->add_child($course);
1028 $information->add_child($settings);
1029 $settings->add_child($setting);
1034 $information->set_source_array(array((object)$info));
1036 $detail->set_source_array($dinfo);
1038 $activity->set_source_array($cinfo['activities']);
1040 $section->set_source_array($cinfo['sections']);
1042 $course->set_source_array($cinfo['course']);
1044 $setting->set_source_array($sinfo);
1046 // Prepare some information to be sent to main moodle_backup.xml file
1047 return $moodle_backup;
1053 * This step will search for all the activity (not calculations, categories nor aggregations) grade items
1054 * and put them to the backup_ids tables, to be used later as base to backup them
1056 class backup_activity_grade_items_to_ids extends backup_execution_step {
1058 protected function define_execution() {
1060 // Fetch all activity grade items
1061 if ($items = grade_item::fetch_all(array(
1062 'itemtype' => 'mod', 'itemmodule' => $this->task->get_modulename(),
1063 'iteminstance' => $this->task->get_activityid(), 'courseid' => $this->task->get_courseid()))) {
1064 // Annotate them in backup_ids
1065 foreach ($items as $item) {
1066 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'grade_item', $item->id);
1073 * This step will annotate all the groups belonging to already annotated groupings
1075 class backup_annotate_groups_from_groupings extends backup_execution_step {
1077 protected function define_execution() {
1080 // Fetch all the annotated groupings
1081 if ($groupings = $DB->get_records('backup_ids_temp', array(
1082 'backupid' => $this->get_backupid(), 'itemname' => 'grouping'))) {
1083 foreach ($groupings as $grouping) {
1084 if ($groups = $DB->get_records('groupings_groups', array(
1085 'groupingid' => $grouping->itemid))) {
1086 foreach ($groups as $group) {
1087 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'group', $group->groupid);
1096 * This step will annotate all the scales belonging to already annotated outcomes
1098 class backup_annotate_scales_from_outcomes extends backup_execution_step {
1100 protected function define_execution() {
1103 // Fetch all the annotated outcomes
1104 if ($outcomes = $DB->get_records('backup_ids_temp', array(
1105 'backupid' => $this->get_backupid(), 'itemname' => 'outcome'))) {
1106 foreach ($outcomes as $outcome) {
1107 if ($scale = $DB->get_record('grade_outcomes', array(
1108 'id' => $outcome->itemid))) {
1109 // Annotate as scalefinal because it's > 0
1110 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'scalefinal', $scale->scaleid);
1118 * This step will generate all the user annotations for the already
1119 * annottated (final) users. Need to do this here because each user
1120 * has its own context and structure tasks only are able to handle
1121 * one context. Also, this step will guarantee that every user has
1122 * its context created (req for other steps)
1124 class backup_annotate_all_user_files extends backup_execution_step {
1126 protected function define_execution() {
1129 // List of fileareas we are going to annotate
1130 // TODO: Change "user_image" file area to the one finally used for user images
1132 'user_private', 'user_profile', 'user_image');
1134 // Fetch all annotated (final) users
1135 $rs = $DB->get_recordset('backup_ids_temp', array(
1136 'backupid' => $this->get_backupid(), 'itemname' => 'userfinal'));
1137 foreach ($rs as $record) {
1138 $userid = $record->itemid;
1139 $userctxid = get_context_instance(CONTEXT_USER, $userid)->id;
1140 // Proceed with every user filearea
1141 foreach ($fileareas as $filearea) {
1142 // We don't need to specify itemid ($userid - 4th param) as far as by
1143 // context we can get all the associated files. See MDL-22092
1144 backup_structure_dbops::annotate_files($this->get_backupid(), $userctxid, $filearea, null);
1152 * structure step in charge of constructing the grades.xml file for all the grade items
1153 * and letters related to one activity
1155 class backup_activity_grades_structure_step extends backup_structure_step {
1157 protected function define_structure() {
1159 // To know if we are including userinfo
1160 $userinfo = $this->get_setting_value('userinfo');
1162 // Define each element separated
1164 $book = new backup_nested_element('activity_gradebook');
1166 $items = new backup_nested_element('grade_items');
1168 $item = new backup_nested_element('grade_item', array('id'), array(
1169 'categoryid', 'itemname', 'itemtype', 'itemmodule',
1170 'iteminstance', 'itemnumber', 'iteminfo', 'idnumber',
1171 'calculation', 'gradetype', 'grademax', 'grademin',
1172 'scaleid', 'outcomeid', 'gradepass', 'multfactor',
1173 'plusfactor', 'aggregationcoef', 'sortorder', 'display',
1174 'decimals', 'hidden', 'locked', 'locktime',
1175 'needsupdate', 'timecreated', 'timemodified'));
1177 $grades = new backup_nested_element('grade_grades');
1179 $grade = new backup_nested_element('grade_grade', array('id'), array(
1180 'userid', 'rawgrade', 'rawgrademax', 'rawgrademin',
1181 'rawscaleid', 'usermodified', 'finalgrade', 'hidden',
1182 'locked', 'locktime', 'exported', 'overridden',
1183 'excluded', 'feedback', 'feedbackformat', 'information',
1184 'informationformat', 'timecreated', 'timemodified'));
1186 $letters = new backup_nested_element('grade_letters');
1188 $letter = new backup_nested_element('grade_letter', 'id', array(
1189 'lowerboundary', 'letter'));
1193 $book->add_child($items);
1194 $items->add_child($item);
1196 $item->add_child($grades);
1197 $grades->add_child($grade);
1199 $book->add_child($letters);
1200 $letters->add_child($letter);
1204 $item->set_source_sql("
1206 FROM {grade_items} gi
1207 JOIN {backup_ids_temp} bi ON gi.id = bi.itemid
1208 WHERE bi.backupid = ?
1209 AND bi.itemname = 'grade_item'", array(backup::VAR_BACKUPID));
1211 // This only happens if we are including user info
1213 $grade->set_source_table('grade_grades', array('itemid' => backup::VAR_PARENTID));
1216 $letter->set_source_table('grade_letters', array('contextid' => backup::VAR_CONTEXTID));
1220 $item->annotate_ids('scalefinal', 'scaleid'); // Straight as scalefinal because it's > 0
1221 $item->annotate_ids('outcome', 'outcomeid');
1223 $grade->annotate_ids('user', 'userid');
1224 $grade->annotate_ids('user', 'usermodified');
1226 // Return the root element (book)