Commit | Line | Data |
---|---|---|
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 | */ | |
28 | class 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 | */ | |
41 | class 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 | */ | |
56 | abstract 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 | */ | |
84 | abstract 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 | */ | |
112 | class 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 | */ | |
156 | class 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 | */ | |
184 | class 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 | */ | |
266 | class 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 | */ | |
322 | class 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 | */ | |
356 | class 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 | */ | |
389 | class 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 | */ | |
423 | class 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 | */ | |
463 | class 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 | */ | |
496 | class 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 | */ | |
528 | class 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 | */ | |
613 | class 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 | */ | |
775 | class 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 | */ | |
823 | class 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 | */ | |
857 | class 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 | */ | |
896 | class 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 | */ | |
916 | class 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*/ | |
950 | class 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 | */ | |
1056 | class 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 | */ | |
1075 | class 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 | */ | |
1098 | class 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 | */ | |
1124 | class 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 | */ | |
1155 | class 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 | } |