Updated the HEAD build version to 20100427
[moodle.git] / backup / moodle2 / backup_stepslib.php
CommitLineData
77547b46
EL
1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * @package moodlecore
20 * @subpackage backup-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
23 */
24
25/**
26 * Define all the backup steps that will be used by common tasks in backup
27 */
28class create_and_clean_temp_stuff extends backup_execution_step {
29
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
35 }
36}
37
38/**
39 * Create the directory where all the task (activity/block...) information will be stored
40 */
41class create_taskbasepath_directory extends backup_execution_step {
42
43 protected function define_execution() {
44 global $CFG;
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);
48 }
49 }
50}
51
52/**
53 * Abtract tructure step, parent of all the activity structure steps. Used to wrap the
54 * activity structure definition within the main <activity ...> tag
55 */
56abstract class backup_activity_structure_step extends backup_structure_step {
57
58 protected function prepare_activity_structure($activitystructure) {
59
60 // Create the wrap element
61 $activity = new backup_nested_element('activity', array('id', 'moduleid', 'modulename', 'contextid'), null);
62
63 // Build the tree
64 $activity->add_child($activitystructure);
65
66 // Set the source
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()));
72
73 $activity->set_source_array($activityarr);
74
75 // Return the root element (activity)
76 return $activity;
77 }
78}
79
80/**
81 * Abtract structure step, parent of all the block structure steps. Used to wrap the
82 * block structure definition within the main <block ...> tag
83 */
84abstract class backup_block_structure_step extends backup_structure_step {
85
86 protected function prepare_block_structure($blockstructure) {
87
88 // Create the wrap element
89 $block = new backup_nested_element('block', array('id', 'blockname', 'contextid'), null);
90
91 // Build the tree
92 $block->add_child($blockstructure);
93
94 // Set the source
95 $blockarr = array((object)array(
96 'id' => $this->task->get_blockid(),
97 'blockname' => $this->task->get_blockname(),
98 'contextid' => $this->task->get_contextid()));
99
100 $block->set_source_array($blockarr);
101
102 // Return the root element (block)
103 return $block;
104 }
105}
106
107/**
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
111 */
112class backup_module_structure_step extends backup_structure_step {
113
114 protected function define_structure() {
115
116 // Define each element separated
117
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'));
124
125 $availinfo = new backup_nested_element('availability_info');
126 $availability = new backup_nested_element('availability', array('id'), array(
127 'sourcecmid', 'requiredcompletion', 'gradeitemid', 'grademin', 'grademax'));
128
129 // Define the tree
130 $module->add_child($availinfo);
131 $availinfo->add_child($availability);
132
133 // Set the sources
134
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));
141
142 $availability->set_source_table('course_modules_availability', array('coursemoduleid' => backup::VAR_MODID));
143
144 // Define annotations
145 $module->annotate_ids('grouping', 'groupingid');
146
147 // Return the root element ($module)
148 return $module;
149 }
150}
151
152/**
153 * structure step that will genereate the section.xml file for the section
154 * annotating files
155 */
156class backup_section_structure_step extends backup_structure_step {
157
158 protected function define_structure() {
159
160 // Define each element separated
161
162 $section = new backup_nested_element('section', array('id'), array(
cd00f9b7 163 'number', 'name', 'summary', 'sequence', 'visible'));
77547b46
EL
164
165 // Define sources
166
167 $section->set_source_table('course_sections', array('id' => backup::VAR_SECTIONID));
168
cd00f9b7
EL
169 // Aliases
170 $section->set_source_alias('section', 'number');
171
77547b46
EL
172 // Set annotations
173 $section->annotate_files(array('course_section'), 'id');
174
175 return $section;
176 }
177}
178
179/**
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)
183 */
184class backup_course_structure_step extends backup_structure_step {
185
186 protected function define_structure() {
187 global $DB;
188
189 // Define each element separated
190
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'));
202
203 $category = new backup_nested_element('category', array('id'), array(
204 'name', 'description'));
205
206 $tags = new backup_nested_element('tags');
207
208 $tag = new backup_nested_element('tag', array('id'), array(
209 'name', 'rawname'));
210
211 $allowedmodules = new backup_nested_element('allowed_modules');
212
213 $module = new backup_nested_element('module', array('modulename'));
214
215 // Build the tree
216
217 $course->add_child($category);
218
219 $course->add_child($tags);
220 $tags->add_child($tag);
221
222 $course->add_child($allowedmodules);
223 $allowedmodules->add_child($module);
224
225 // Set the sources
226
227 $courserec = $DB->get_record('course', array('id' => $this->task->get_courseid()));
228 $courserec->contextid = $this->task->get_contextid();
229
230 $course->set_source_array(array($courserec));
231
232 $categoryrec = $DB->get_record('course_categories', array('id' => $courserec->category));
233
234 $category->set_source_array(array($categoryrec));
235
236 $tag->set_source_sql('SELECT t.id, t.name, t.rawname
237 FROM {tag} t
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));
243
244 $module->set_source_sql('SELECT m.name AS modulename
245 FROM {modules} m
246 JOIN {course_allowed_modules} cam ON m.id = cam.module
247 WHERE course = ?', array(backup::VAR_COURSEID));
248
249 // Some annotations
250
251 $course->annotate_ids('role', 'defaultrole');
252 $course->annotate_ids('grouping', 'defaultgroupingid');
253
254 $course->annotate_files(array('course_summary', 'course_content'), null);
255
256 // Return root element ($course)
257
258 return $course;
259 }
260}
261
262/**
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
265 */
266class backup_roles_structure_step extends backup_structure_step {
267
268 protected function define_structure() {
269
270 // To know if we are including role assignments
271 $roleassignments = $this->get_setting_value('role_assignments');
272
273 // Define each element separated
274
275 $roles = new backup_nested_element('roles');
276
277 $overrides = new backup_nested_element('role_overrides');
278
279 $override = new backup_nested_element('override', array('id'), array(
280 'roleid', 'capability', 'permission', 'timemodified',
281 'modifierid'));
282
283 $assignments = new backup_nested_element('role_assignments');
284
285 $assignment = new backup_nested_element('assignment', array('id'), array(
286 'roleid', 'userid', 'hidden', 'timestart',
287 'timeend', 'timemodified', 'modifierid', 'enrol',
288 'sortorder'));
289
290 // Build the tree
291 $roles->add_child($overrides);
292 $roles->add_child($assignments);
293
294 $overrides->add_child($override);
295 $assignments->add_child($assignment);
296
297 // Define sources
298
299 $override->set_source_table('role_capabilities', array('contextid' => backup::VAR_CONTEXTID));
300
301 // Assignments only added if specified
302 if ($roleassignments) {
303 $assignment->set_source_table('role_assignments', array('contextid' => backup::VAR_CONTEXTID));
304 }
305
306 // Define id annotations
307 $override->annotate_ids('role', 'roleid');
308
309 $assignment->annotate_ids('role', 'roleid');
310
311 $assignment->annotate_ids('user', 'userid');
312
313 return $roles;
314 }
315}
316
317/**
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
321 */
322class backup_final_roles_structure_step extends backup_structure_step {
323
324 protected function define_structure() {
325
326 // Define elements
327
328 $rolesdef = new backup_nested_element('roles_definition');
329
330 $role = new backup_nested_element('role', array('id'), array(
331 'name', 'shortname', 'nameincourse', 'description',
332 'sortorder', 'archetype'));
333
334 // Build the tree
335
336 $rolesdef->add_child($role);
337
338 // Define sources
339
340 $role->set_source_sql("SELECT r.*, rn.name AS nameincourse
341 FROM {role} r
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));
346
347 // Return main element (rolesdef)
348 return $rolesdef;
349 }
350}
351
352/**
353 * structure step that will generate the scales.xml containing the
354 * list of scales used along the whole backup process.
355 */
356class backup_final_scales_structure_step extends backup_structure_step {
357
358 protected function define_structure() {
359
360 // Define elements
361
362 $scalesdef = new backup_nested_element('scales_definition');
363
364 $scale = new backup_nested_element('scale', array('id'), array(
365 'courseid', 'userid', 'name', 'scale',
366 'description', 'descriptionformat', 'timemodified'));
367
368 // Build the tree
369
370 $scalesdef->add_child($scale);
371
372 // Define sources
373
374 $scale->set_source_sql("SELECT s.*
375 FROM {scale} 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));
379
380 // Return main element (scalesdef)
381 return $scalesdef;
382 }
383}
384
385/**
386 * structure step that will generate the outcomes.xml containing the
387 * list of outcomes used along the whole backup process.
388 */
389class backup_final_outcomes_structure_step extends backup_structure_step {
390
391 protected function define_structure() {
392
393 // Define elements
394
395 $outcomesdef = new backup_nested_element('outcomes_definition');
396
397 $outcome = new backup_nested_element('outcome', array('id'), array(
398 'courseid', 'userid', 'shortname', 'fullname',
399 'scaleid', 'description', 'descriptionformat', 'timecreated',
400 'timemodified','usermodified'));
401
402 // Build the tree
403
404 $outcomesdef->add_child($outcome);
405
406 // Define sources
407
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));
413
414 // Return main element (outcomesdef)
415 return $outcomesdef;
416 }
417}
418
419/**
420 * structure step in charge of constructing the filters.xml file for all the filters found
421 * in activity
422 */
423class backup_filters_structure_step extends backup_structure_step {
424
425 protected function define_structure() {
426
427 // Define each element separated
428
429 $filters = new backup_nested_element('filters');
430
431 $actives = new backup_nested_element('filter_actives');
432
433 $active = new backup_nested_element('filter_active', null, array('filter', 'active'));
434
435 $configs = new backup_nested_element('filter_configs');
436
437 $config = new backup_nested_element('filter_config', null, array('filter', 'name', 'value'));
438
439 // Build the tree
440
441 $filters->add_child($actives);
442 $filters->add_child($configs);
443
444 $actives->add_child($active);
445 $configs->add_child($config);
446
447 // Define sources
448
449 list($activearr, $configarr) = filter_get_all_local_settings($this->task->get_contextid());
450
451 $active->set_source_array($activearr);
452 $config->set_source_array($configarr);
453
454 // Return the root element (filters)
455 return $filters;
456 }
457}
458
459/**
460 * structure step in charge of constructing the comments.xml file for all the comments found
461 * in a given context
462 */
463class backup_comments_structure_step extends backup_structure_step {
464
465 protected function define_structure() {
466
467 // Define each element separated
468
469 $comments = new backup_nested_element('comments');
470
471 $comment = new backup_nested_element('comment', array('id'), array(
472 'commentarea', 'itemid', 'content', 'format',
473 'userid', 'timecreated'));
474
475 // Build the tree
476
477 $comments->add_child($comment);
478
479 // Define sources
480
481 $comment->set_source_table('comments', array('contextid' => backup::VAR_CONTEXTID));
482
483 // Define id annotations
484
485 $comment->annotate_ids('user', 'userid');
486
487 // Return the root element (comments)
488 return $comments;
489 }
490}
491
492/**
493 * structure step in charge if constructing the completion.xml file for all the users completion
494 * information in a given activity
495 */
496class backup_userscompletion_structure_step extends backup_structure_step {
497
498 protected function define_structure() {
499
500 // Define each element separated
501
502 $completions = new backup_nested_element('completions');
503
504 $completion = new backup_nested_element('completion', array('id'), array(
505 'userid', 'completionstate', 'viewed', 'timemodified'));
506
507 // Build the tree
508
509 $completions->add_child($completion);
510
511 // Define sources
512
513 $completion->set_source_table('course_modules_completion', array('coursemoduleid' => backup::VAR_MODID));
514
515 // Define id annotations
516
517 $completion->annotate_ids('user', 'userid');
518
519 // Return the root element (completions)
520 return $completions;
521 }
522}
523
524/**
525 * structure step in charge of constructing the main groups.xml file for all the groups and
526 * groupings information already annotated
527 */
528class backup_groups_structure_step extends backup_structure_step {
529
530 protected function define_structure() {
531
532 // To know if we are including users
533 $users = $this->get_setting_value('users');
534
535 // Define each element separated
536
537 $groups = new backup_nested_element('groups');
538
539 $group = new backup_nested_element('group', array('id'), array(
540 'name', 'description', 'descriptionformat', 'enrolmentkey',
541 'picture', 'hidepicture', 'timecreated', 'timemodified'));
542
543 $members = new backup_nested_element('group_members');
544
545 $member = new backup_nested_element('group_member', array('id'), array(
546 'userid', 'timeadded'));
547
548 $groupings = new backup_nested_element('groupings');
549
550 $grouping = new backup_nested_element('grouping', 'id', array(
551 'name', 'description', 'descriptionformat', 'configdata',
552 'timecreated', 'timemodified'));
553
554 $groupinggroups = new backup_nested_element('grouping_groups');
555
556 $groupinggroup = new backup_nested_element('grouping_group', array('id'), array(
557 'groupid', 'timeadded'));
558
559 // Build the tree
560
561 $groups->add_child($group);
562 $groups->add_child($groupings);
563
564 $group->add_child($members);
565 $members->add_child($member);
566
567 $groupings->add_child($grouping);
568 $grouping->add_child($groupinggroups);
569 $groupinggroups->add_child($groupinggroup);
570
571 // Define sources
572
573 $group->set_source_sql("
574 SELECT g.*
575 FROM {groups} g
576 JOIN {backup_ids_temp} bi ON g.id = bi.itemid
577 WHERE bi.backupid = ?
578 AND bi.itemname = 'groupfinal'", array(backup::VAR_BACKUPID));
579
580 // This only happens if we are including users
581 if ($users) {
582 $member->set_source_table('groups_members', array('groupid' => backup::VAR_PARENTID));
583 }
584
585 $grouping->set_source_sql("
586 SELECT g.*
587 FROM {groupings} g
588 JOIN {backup_ids_temp} bi ON g.id = bi.itemid
589 WHERE bi.backupid = ?
590 AND bi.itemname = 'groupingfinal'", array(backup::VAR_BACKUPID));
591
592 $groupinggroup->set_source_table('groupings_groups', array('groupingid' => backup::VAR_PARENTID));
593
594 // Define id annotations (as final)
595
596 $member->annotate_ids('userfinal', 'userid');
597
598 // Define file annotations
599
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');
602
603 // Return the root element (groups)
604 return $groups;
605 }
606}
607
608/**
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
611 * overrides.
612 */
613class backup_users_structure_step extends backup_structure_step {
614
615 protected function define_structure() {
616 global $CFG;
617
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');
622
623 // Define each element separated
624
625 $users = new backup_nested_element('users');
626
627 // Create the array of user fields by hand, as far as we have various bits to control
628 // anonymize option, password backup, mnethostid...
629
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');
638
639 // Then, the fields potentially needing anonymization
640 $anonfields = array(
641 'username', 'idnumber', 'firstname', 'lastname',
642 'email', 'emailstop', 'lastip', 'picture',
643 'url', 'description', 'description_format', 'imagealt', 'auth');
644
645 // Add anonymized fields to $userfields with custom final element
646 foreach ($anonfields as $field) {
647 if ($anonymize) {
648 $userfields[] = new anonymizer_final_element($field);
649 } else {
650 $userfields[] = $field; // No anonymization, normally added
651 }
652 }
653
654 // mnethosturl requires special handling (custom final element)
655 $userfields[] = new mnethosturl_final_element('mnethosturl');
656
657 // password added conditionally
658 if (!empty($CFG->includeuserpasswordsinbackup)) {
659 $userfields[] = 'password';
660 }
661
662 // Merge all the fields
663 $userfields = array_merge($userfields, $normalfields);
664
665 $user = new backup_nested_element('user', array('id', 'contextid'), $userfields);
666
667 $customfields = new backup_nested_element('custom_fields');
668
669 $customfield = new backup_nested_element('custom_field', array('id'), array(
670 'field_name', 'field_type', 'field_data'));
671
672 $tags = new backup_nested_element('tags');
673
674 $tag = new backup_nested_element('tag', array('id'), array(
675 'name', 'rawname'));
676
677 $preferences = new backup_nested_element('preferences');
678
679 $preference = new backup_nested_element('preference', array('id'), array(
680 'name', 'value'));
681
682 $roles = new backup_nested_element('roles');
683
684 $overrides = new backup_nested_element('role_overrides');
685
686 $override = new backup_nested_element('override', array('id'), array(
687 'roleid', 'capability', 'permission', 'timemodified',
688 'modifierid'));
689
690 $assignments = new backup_nested_element('role_assignments');
691
692 $assignment = new backup_nested_element('assignment', array('id'), array(
693 'roleid', 'userid', 'hidden', 'timestart',
694 'timeend', 'timemodified', 'modifierid', 'enrol',
695 'sortorder'));
696
697 // Build the tree
698
699 $users->add_child($user);
700
701 $user->add_child($customfields);
702 $customfields->add_child($customfield);
703
704 $user->add_child($tags);
705 $tags->add_child($tag);
706
707 $user->add_child($preferences);
708 $preferences->add_child($preference);
709
710 $user->add_child($roles);
711
712 $roles->add_child($overrides);
713 $roles->add_child($assignments);
714
715 $overrides->add_child($override);
716 $assignments->add_child($assignment);
717
718 // Define sources
719
720 $user->set_source_sql('SELECT u.*, c.id AS contextid, m.wwwroot AS mnethosturl
721 FROM {user} u
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 = ?
726 AND bi.itemname = ?
727 AND c.contextlevel = ?', array(
728 $this->is_sqlparam($this->get_backupid()),
729 $this->is_sqlparam('userfinal'),
730 $this->is_sqlparam(CONTEXT_USER)));
731
732 // All the rest on information is only added if we arent
733 // in an anonymized backup
734 if (!$anonymize) {
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));
739
740 $customfield->set_source_alias('shortname', 'field_name');
741 $customfield->set_source_alias('datatype', 'field_type');
742 $customfield->set_source_alias('data', 'field_data');
743
744 $tag->set_source_sql('SELECT t.id, t.name, t.rawname
745 FROM {tag} t
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));
751
752 $preference->set_source_table('user_preferences', array('userid' => backup::VAR_PARENTID));
753
754 $override->set_source_table('role_capabilities', array('contextid' => '/users/user/contextid'));
755
756 // Assignments only added if specified
757 if ($roleassignments) {
758 $assignment->set_source_table('role_assignments', array('contextid' => '/users/user/contextid'));
759 }
760
761 // Define id annotations (as final)
762 $override->annotate_ids('rolefinal', 'roleid');
763 }
764
765 // Return root element (users)
766 return $users;
767 }
768}
769
770/**
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)
774 */
775class backup_block_instance_structure_step extends backup_structure_step {
776
777 protected function define_structure() {
778 global $DB;
779
780 // Define each element separated
781
782 $block = new backup_nested_element('block', array('id', 'version'), array(
783 'blockname', 'showinsubcontexts', 'pagetypepattern', 'subpagepattern',
784 'defaultregion', 'defaultweight', 'configdata'));
785
786 $positions = new backup_nested_element('block_positions', null, array(
787 'contextid', 'pagetype', 'subpage', 'visible',
788 'region', 'weight'));
789
790 // Build the tree
791
792 $block->add_child($positions);
793
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);
801 }
802 }
803 $blockrec->configdata = base64_encode(serialize((object)$configdata));
804 }
805 // Get the version of the block
806 $blockrec->version = $DB->get_field('block', 'version', array('name' => $this->task->get_blockname()));
807
808 // Define sources
809
810 $block->set_source_array(array($blockrec));
811
812 $positions->set_source_table('block_positions', array('blockinstanceid' => backup::VAR_PARENTID));
813
814 // Return the root element (block)
815 return $block;
816 }
817}
818
819/**
820 * structure step in charge of constructing the logs.xml file for all the log records found
821 * in activity
822 */
823class backup_activity_logs_structure_step extends backup_structure_step {
824
825 protected function define_structure() {
826
827 // Define each element separated
828
829 $logs = new backup_nested_element('logs');
830
831 $log = new backup_nested_element('log', array('id'), array(
832 'time', 'userid', 'ip', 'module',
833 'action', 'url', 'info'));
834
835 // Build the tree
836
837 $logs->add_child($log);
838
839 // Define sources
840
841 $log->set_source_table('log', array('cmid' => backup::VAR_MODID));
842
843 // Annotations
844 // NOTE: We don't annotate users from logs as far as they MUST be
845 // always annotated by the activity.
846
847 // Return the root element (logs)
848
849 return $logs;
850 }
851}
852
853/**
854 * structure in charge of constructing the inforef.xml file for all the items we want
855 * to have referenced there (users, roles, files...)
856 */
857class backup_inforef_structure_step extends backup_structure_step {
858
859 protected function define_structure() {
860
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');
864
865 // Build the tree
866
867 $inforef = new backup_nested_element('inforef');
868
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("
877 SELECT itemid AS id
878 FROM {backup_ids_temp}
879 WHERE backupid = ?
880 AND itemname = ?",
881 array(backup::VAR_BACKUPID, $this->is_sqlparam($itemname)));
882 }
883 }
884
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.
888 return $inforef;
889 }
890}
891
892/**
893 * This step will get all the annotations already processed to inforef.xml file and
894 * transform them into 'final' annotations.
895 */
896class move_inforef_annotations_to_final extends backup_execution_step {
897
898 protected function define_execution() {
899
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) {
904 // Delegate to dbops
905 backup_structure_dbops::move_annotations_to_final($this->get_backupid(), $itemname);
906 }
907 }
908}
909
910/**
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
914 * to backup storage
915 */
916class backup_final_files_structure_step extends backup_structure_step {
917
918 protected function define_structure() {
919
920 // Define elements
921
922 $files = new backup_nested_element('files');
923
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'));
929
930 // Build the tree
931
932 $files->add_child($file);
933
934 // Define sources
935
936 $file->set_source_sql("SELECT f.*
937 FROM {files} 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));
941
942 return $files;
943 }
944}
945
946/**
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*/
950class backup_main_structure_step extends backup_structure_step {
951
952 protected function define_structure() {
953
954 global $CFG;
955
956 $info = array();
957
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();
968
969 // Get more information from controller
970 list($dinfo, $cinfo, $sinfo) = backup_controller_dbops::get_moodle_backup_information($this->get_backupid());
971
972 // Define elements
973
974 $moodle_backup = new backup_nested_element('moodle_backup');
975
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'));
980
981 $details = new backup_nested_element('details');
982
983 $detail = new backup_nested_element('detail', array('backup_id'), array(
984 'type', 'format', 'interactive', 'mode',
985 'execution', 'executiontime'));
986
987 $contents = new backup_nested_element('contents');
988
989 $activities = new backup_nested_element('activities');
990
991 $activity = new backup_nested_element('activity', null, array(
992 'moduleid', 'sectionid', 'modulename', 'title',
993 'directory'));
994
995 $sections = new backup_nested_element('sections');
996
997 $section = new backup_nested_element('section', null, array(
998 'sectionid', 'title', 'directory'));
999
1000 $course = new backup_nested_element('course', null, array(
1001 'courseid', 'title', 'directory'));
1002
1003 $settings = new backup_nested_element('settings');
1004
1005 $setting = new backup_nested_element('setting', null, array(
1006 'level', 'activity', 'name', 'value'));
1007
1008 // Build the tree
1009
1010 $moodle_backup->add_child($information);
1011
1012 $information->add_child($details);
1013 $details->add_child($detail);
1014
1015 $information->add_child($contents);
1016 if (!empty($cinfo['activities'])) {
1017 $contents->add_child($activities);
1018 $activities->add_child($activity);
1019 }
1020 if (!empty($cinfo['sections'])) {
1021 $contents->add_child($sections);
1022 $sections->add_child($section);
1023 }
1024 if (!empty($cinfo['course'])) {
1025 $contents->add_child($course);
1026 }
1027
1028 $information->add_child($settings);
1029 $settings->add_child($setting);
1030
1031
1032 // Set the sources
1033
1034 $information->set_source_array(array((object)$info));
1035
1036 $detail->set_source_array($dinfo);
1037
1038 $activity->set_source_array($cinfo['activities']);
1039
1040 $section->set_source_array($cinfo['sections']);
1041
1042 $course->set_source_array($cinfo['course']);
1043
1044 $setting->set_source_array($sinfo);
1045
1046 // Prepare some information to be sent to main moodle_backup.xml file
1047 return $moodle_backup;
1048 }
1049
1050}
1051
1052/**
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
1055 */
1056class backup_activity_grade_items_to_ids extends backup_execution_step {
1057
1058 protected function define_execution() {
1059
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);
1067 }
1068 }
1069 }
1070}
1071
1072/**
1073 * This step will annotate all the groups belonging to already annotated groupings
1074 */
1075class backup_annotate_groups_from_groupings extends backup_execution_step {
1076
1077 protected function define_execution() {
1078 global $DB;
1079
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);
1088 }
1089 }
1090 }
1091 }
1092 }
1093}
1094
1095/**
1096 * This step will annotate all the scales belonging to already annotated outcomes
1097 */
1098class backup_annotate_scales_from_outcomes extends backup_execution_step {
1099
1100 protected function define_execution() {
1101 global $DB;
1102
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);
1111 }
1112 }
1113 }
1114 }
1115}
1116
1117/**
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)
1123 */
1124class backup_annotate_all_user_files extends backup_execution_step {
1125
1126 protected function define_execution() {
1127 global $DB;
1128
1129 // List of fileareas we are going to annotate
1130 // TODO: Change "user_image" file area to the one finally used for user images
1131 $fileareas = array(
1132 'user_private', 'user_profile', 'user_image');
1133
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);
1145 }
1146 }
1147 $rs->close();
1148 }
1149}
1150
1151/**
1152 * structure step in charge of constructing the grades.xml file for all the grade items
1153 * and letters related to one activity
1154 */
1155class backup_activity_grades_structure_step extends backup_structure_step {
1156
1157 protected function define_structure() {
1158
1159 // To know if we are including userinfo
1160 $userinfo = $this->get_setting_value('userinfo');
1161
1162 // Define each element separated
1163
1164 $book = new backup_nested_element('activity_gradebook');
1165
1166 $items = new backup_nested_element('grade_items');
1167
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'));
1176
1177 $grades = new backup_nested_element('grade_grades');
1178
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'));
1185
1186 $letters = new backup_nested_element('grade_letters');
1187
1188 $letter = new backup_nested_element('grade_letter', 'id', array(
1189 'lowerboundary', 'letter'));
1190
1191 // Build the tree
1192
1193 $book->add_child($items);
1194 $items->add_child($item);
1195
1196 $item->add_child($grades);
1197 $grades->add_child($grade);
1198
1199 $book->add_child($letters);
1200 $letters->add_child($letter);
1201
1202 // Define sources
1203
1204 $item->set_source_sql("
1205 SELECT gi.*
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));
1210
1211 // This only happens if we are including user info
1212 if ($userinfo) {
1213 $grade->set_source_table('grade_grades', array('itemid' => backup::VAR_PARENTID));
1214 }
1215
1216 $letter->set_source_table('grade_letters', array('contextid' => backup::VAR_CONTEXTID));
1217
1218 // Annotations
1219
1220 $item->annotate_ids('scalefinal', 'scaleid'); // Straight as scalefinal because it's > 0
1221 $item->annotate_ids('outcome', 'outcomeid');
1222
1223 $grade->annotate_ids('user', 'userid');
1224 $grade->annotate_ids('user', 'usermodified');
1225
1226 // Return the root element (book)
1227
1228 return $book;
1229 }
1230}