MDL-23478 backup - adding support for fileareas to blocks
[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 */
2de3539b
EL
28
29/**
30 * create the temp dir where backup/restore will happen,
31 * delete old directories and create temp ids table
32 */
77547b46
EL
33class create_and_clean_temp_stuff extends backup_execution_step {
34
35 protected function define_execution() {
36 backup_helper::check_and_create_backup_dir($this->get_backupid());// Create backup temp dir
37 backup_helper::clear_backup_dir($this->get_backupid()); // Empty temp dir, just in case
38 backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60)); // Delete > 4 hours temp dirs
39 backup_controller_dbops::create_backup_ids_temp_table($this->get_backupid()); // Create ids temp table
40 }
41}
42
2de3539b
EL
43/**
44 * delete the temp dir used by backup/restore (conditionally),
45 * delete old directories and drop tem ids table. Note we delete
39b5371c 46 * the directory but not the corresponding log file that will be
2de3539b
EL
47 * there for, at least, 4 hours - only delete_old_backup_dirs()
48 * deletes log files (for easier access to them)
49 */
50class drop_and_clean_temp_stuff extends backup_execution_step {
51
52 protected function define_execution() {
53 global $CFG;
54 backup_controller_dbops::drop_backup_ids_temp_table($this->get_backupid()); // Drop ids temp table
55 backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60)); // Delete > 4 hours temp dirs
56 if (empty($CFG->keeptempdirectoriesonbackup)) { // Conditionally
57 backup_helper::delete_backup_dir($this->get_backupid()); // Empty backup dir
58 }
59 }
60}
61
77547b46
EL
62/**
63 * Create the directory where all the task (activity/block...) information will be stored
64 */
65class create_taskbasepath_directory extends backup_execution_step {
66
67 protected function define_execution() {
68 global $CFG;
69 $basepath = $this->task->get_taskbasepath();
70 if (!check_dir_exists($basepath, true, true)) {
71 throw new backup_step_exception('cannot_create_taskbasepath_directory', $basepath);
72 }
73 }
74}
75
76/**
39b5371c 77 * Abstract structure step, parent of all the activity structure steps. Used to wrap the
060df4c8
EL
78 * activity structure definition within the main <activity ...> tag. Also provides
79 * subplugin support for activities (that must be properly declared)
77547b46
EL
80 */
81abstract class backup_activity_structure_step extends backup_structure_step {
82
4abf04ea
EL
83 /**
84 * Add subplugin structure to any element in the activity backup tree
85 *
86 * @param string $subplugintype type of subplugin as defined in activity db/subplugins.php
87 * @param backup_nested_element $element element in the activity backup tree that
88 * we are going to add subplugin information to
89 * @param bool $multiple to define if multiple subplugins can produce information
90 * for each instance of $element (true) or no (false)
91 */
92 protected function add_subplugin_structure($subplugintype, $element, $multiple) {
060df4c8
EL
93
94 global $CFG;
95
4abf04ea 96 // Check the requested subplugintype is a valid one
060df4c8
EL
97 $subpluginsfile = $CFG->dirroot . '/mod/' . $this->task->get_modulename() . '/db/subplugins.php';
98 if (!file_exists($subpluginsfile)) {
99 throw new backup_step_exception('activity_missing_subplugins_php_file', $this->task->get_modulename());
100 }
101 include($subpluginsfile);
4abf04ea
EL
102 if (!array_key_exists($subplugintype, $subplugins)) {
103 throw new backup_step_exception('incorrect_subplugin_type', $subplugintype);
060df4c8
EL
104 }
105
106 // Arrived here, subplugin is correct, let's create the optigroup
4abf04ea 107 $optigroupname = $subplugintype . '_' . $element->get_name() . '_subplugin';
060df4c8 108 $optigroup = new backup_optigroup($optigroupname, null, $multiple);
f2e34ee5 109 $element->add_child($optigroup); // Add optigroup to stay connected since beginning
060df4c8 110
39b5371c 111 // Get all the optigroup_elements, looking across all the subplugin dirs
060df4c8 112 $elements = array();
4abf04ea 113 $subpluginsdirs = get_plugin_list($subplugintype);
060df4c8 114 foreach ($subpluginsdirs as $name => $subpluginsdir) {
4abf04ea 115 $classname = 'backup_' . $subplugintype . '_' . $name . '_subplugin';
060df4c8
EL
116 $backupfile = $subpluginsdir . '/backup/moodle2/' . $classname . '.class.php';
117 if (file_exists($backupfile)) {
118 require_once($backupfile);
f2e34ee5
EL
119 $backupsubplugin = new $classname($subplugintype, $name, $optigroup);
120 // Add subplugin returned structure to optigroup
121 $backupsubplugin->define_subplugin_structure($element->get_name());
060df4c8
EL
122 }
123 }
060df4c8
EL
124 }
125
4abf04ea
EL
126 /**
127 * Wraps any activity backup structure within the common 'activity' element
128 * that will include common to all activities information like id, context...
129 */
77547b46
EL
130 protected function prepare_activity_structure($activitystructure) {
131
132 // Create the wrap element
133 $activity = new backup_nested_element('activity', array('id', 'moduleid', 'modulename', 'contextid'), null);
134
135 // Build the tree
136 $activity->add_child($activitystructure);
137
138 // Set the source
139 $activityarr = array((object)array(
140 'id' => $this->task->get_activityid(),
141 'moduleid' => $this->task->get_moduleid(),
142 'modulename' => $this->task->get_modulename(),
143 'contextid' => $this->task->get_contextid()));
144
145 $activity->set_source_array($activityarr);
146
147 // Return the root element (activity)
148 return $activity;
149 }
150}
151
152/**
39b5371c 153 * Abstract structure step, parent of all the block structure steps. Used to wrap the
77547b46
EL
154 * block structure definition within the main <block ...> tag
155 */
156abstract class backup_block_structure_step extends backup_structure_step {
157
158 protected function prepare_block_structure($blockstructure) {
159
160 // Create the wrap element
161 $block = new backup_nested_element('block', array('id', 'blockname', 'contextid'), null);
162
163 // Build the tree
164 $block->add_child($blockstructure);
165
166 // Set the source
167 $blockarr = array((object)array(
168 'id' => $this->task->get_blockid(),
169 'blockname' => $this->task->get_blockname(),
170 'contextid' => $this->task->get_contextid()));
171
172 $block->set_source_array($blockarr);
173
174 // Return the root element (block)
175 return $block;
176 }
177}
178
179/**
180 * structure step that will generate the module.xml file for the activity,
39b5371c 181 * accumulating various information about the activity, annotating groupings
77547b46
EL
182 * and completion/avail conf
183 */
184class backup_module_structure_step extends backup_structure_step {
185
186 protected function define_structure() {
187
188 // Define each element separated
189
190 $module = new backup_nested_element('module', array('id', 'version'), array(
191 'modulename', 'sectionid', 'sectionnumber', 'idnumber',
192 'added', 'score', 'indent', 'visible',
193 'visibleold', 'groupmode', 'groupingid', 'groupmembersonly',
194 'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected',
195 'availablefrom', 'availableuntil', 'showavailability'));
196
197 $availinfo = new backup_nested_element('availability_info');
198 $availability = new backup_nested_element('availability', array('id'), array(
199 'sourcecmid', 'requiredcompletion', 'gradeitemid', 'grademin', 'grademax'));
200
201 // Define the tree
202 $module->add_child($availinfo);
203 $availinfo->add_child($availability);
204
205 // Set the sources
206
207 $module->set_source_sql('
208 SELECT cm.*, m.version, m.name AS modulename, s.id AS sectionid, s.section AS sectionnumber
209 FROM {course_modules} cm
210 JOIN {modules} m ON m.id = cm.module
211 JOIN {course_sections} s ON s.id = cm.section
212 WHERE cm.id = ?', array(backup::VAR_MODID));
213
214 $availability->set_source_table('course_modules_availability', array('coursemoduleid' => backup::VAR_MODID));
215
216 // Define annotations
217 $module->annotate_ids('grouping', 'groupingid');
218
219 // Return the root element ($module)
220 return $module;
221 }
222}
223
224/**
39b5371c 225 * structure step that will generate the section.xml file for the section
77547b46
EL
226 * annotating files
227 */
228class backup_section_structure_step extends backup_structure_step {
229
230 protected function define_structure() {
231
232 // Define each element separated
233
234 $section = new backup_nested_element('section', array('id'), array(
e34a326f 235 'number', 'name', 'summary', 'summaryformat', 'sequence', 'visible'));
77547b46
EL
236
237 // Define sources
238
239 $section->set_source_table('course_sections', array('id' => backup::VAR_SECTIONID));
240
cd00f9b7
EL
241 // Aliases
242 $section->set_source_alias('section', 'number');
243
77547b46 244 // Set annotations
64f93798 245 $section->annotate_files('course', 'section', 'id');
77547b46
EL
246
247 return $section;
248 }
249}
250
251/**
252 * structure step that will generate the course.xml file for the course, including
df997f84 253 * course category reference, tags, modules restriction information
77547b46
EL
254 * and some annotations (files & groupings)
255 */
256class backup_course_structure_step extends backup_structure_step {
257
258 protected function define_structure() {
259 global $DB;
260
261 // Define each element separated
262
263 $course = new backup_nested_element('course', array('id', 'contextid'), array(
df997f84 264 'shortname', 'fullname', 'idnumber',
77547b46 265 'summary', 'summaryformat', 'format', 'showgrades',
df997f84 266 'newsitems', 'startdate',
77547b46
EL
267 'numsections', 'marker', 'maxbytes', 'showreports',
268 'visible', 'hiddensections', 'groupmode', 'groupmodeforce',
df997f84
PS
269 'defaultgroupingid', 'lang', 'theme',
270 'timecreated', 'timemodified',
271 'requested', 'restrictmodules',
395dae30 272 'enablecompletion', 'completionstartonenrol', 'completionnotify'));
77547b46
EL
273
274 $category = new backup_nested_element('category', array('id'), array(
275 'name', 'description'));
276
277 $tags = new backup_nested_element('tags');
278
279 $tag = new backup_nested_element('tag', array('id'), array(
280 'name', 'rawname'));
281
282 $allowedmodules = new backup_nested_element('allowed_modules');
283
ce28d999 284 $module = new backup_nested_element('module', array(), array('modulename'));
77547b46
EL
285
286 // Build the tree
287
288 $course->add_child($category);
289
290 $course->add_child($tags);
291 $tags->add_child($tag);
292
293 $course->add_child($allowedmodules);
294 $allowedmodules->add_child($module);
295
296 // Set the sources
297
298 $courserec = $DB->get_record('course', array('id' => $this->task->get_courseid()));
299 $courserec->contextid = $this->task->get_contextid();
300
301 $course->set_source_array(array($courserec));
302
303 $categoryrec = $DB->get_record('course_categories', array('id' => $courserec->category));
304
305 $category->set_source_array(array($categoryrec));
306
307 $tag->set_source_sql('SELECT t.id, t.name, t.rawname
308 FROM {tag} t
309 JOIN {tag_instance} ti ON ti.tagid = t.id
310 WHERE ti.itemtype = ?
311 AND ti.itemid = ?', array(
c0bd6249 312 backup_helper::is_sqlparam('course'),
77547b46
EL
313 backup::VAR_PARENTID));
314
315 $module->set_source_sql('SELECT m.name AS modulename
316 FROM {modules} m
317 JOIN {course_allowed_modules} cam ON m.id = cam.module
318 WHERE course = ?', array(backup::VAR_COURSEID));
319
320 // Some annotations
321
77547b46
EL
322 $course->annotate_ids('grouping', 'defaultgroupingid');
323
64f93798
PS
324 $course->annotate_files('course', 'summary', null);
325 $course->annotate_files('course', 'legacy', null);
77547b46
EL
326
327 // Return root element ($course)
328
329 return $course;
330 }
331}
332
cb34c4cd
PS
333/**
334 * structure step that will generate the enrolments.xml file for the given course
335 */
336class backup_enrolments_structure_step extends backup_structure_step {
337
338 protected function define_structure() {
339
340 // To know if we are including users
341 $users = $this->get_setting_value('users');
342
343 // Define each element separated
344
345 $enrolments = new backup_nested_element('enrolments');
346
347 $enrols = new backup_nested_element('enrols');
348
349 $enrol = new backup_nested_element('enrol', array('id'), array(
101bd9c9 350 'enrol', 'status', 'sortorder', 'name', 'enrolperiod', 'enrolstartdate',
cb34c4cd
PS
351 'enrolenddate', 'expirynotify', 'expirytreshold', 'notifyall',
352 'password', 'cost', 'currency', 'roleid', 'customint1', 'customint2', 'customint3',
353 'customint4', 'customchar1', 'customchar2', 'customdec1', 'customdec2',
354 'customtext1', 'customtext2', 'timecreated', 'timemodified'));
355
356 $userenrolments = new backup_nested_element('user_enrolments');
357
358 $enrolment = new backup_nested_element('enrolment', array('id'), array(
101bd9c9 359 'status', 'userid', 'timestart', 'timeend', 'modifierid',
cb34c4cd
PS
360 'timemodified'));
361
362 // Build the tree
363 $enrolments->add_child($enrols);
364 $enrols->add_child($enrol);
365 $enrol->add_child($userenrolments);
366 $userenrolments->add_child($enrolment);
367
368 // Define sources
369
370 $enrol->set_source_table('enrol', array('courseid' => backup::VAR_COURSEID));
371
101bd9c9 372 // User enrolments only added only if users included
cb34c4cd
PS
373 if ($users) {
374 $enrolment->set_source_table('user_enrolments', array('enrolid' => backup::VAR_PARENTID));
02eca29c 375 $enrolment->annotate_ids('user', 'userid');
cb34c4cd
PS
376 }
377
902944a8
PS
378 $enrol->annotate_ids('role', 'roleid');
379
cb34c4cd
PS
380 //TODO: let plugins annotate custom fields too and add more children
381
382 return $enrolments;
383 }
384}
385
77547b46
EL
386/**
387 * structure step that will generate the roles.xml file for the given context, observing
388 * the role_assignments setting to know if that part needs to be included
389 */
390class backup_roles_structure_step extends backup_structure_step {
391
392 protected function define_structure() {
393
394 // To know if we are including role assignments
395 $roleassignments = $this->get_setting_value('role_assignments');
396
397 // Define each element separated
398
399 $roles = new backup_nested_element('roles');
400
401 $overrides = new backup_nested_element('role_overrides');
402
403 $override = new backup_nested_element('override', array('id'), array(
404 'roleid', 'capability', 'permission', 'timemodified',
405 'modifierid'));
406
407 $assignments = new backup_nested_element('role_assignments');
408
409 $assignment = new backup_nested_element('assignment', array('id'), array(
cb34c4cd 410 'roleid', 'userid', 'timemodified', 'modifierid', 'component', 'itemid',
77547b46
EL
411 'sortorder'));
412
413 // Build the tree
414 $roles->add_child($overrides);
415 $roles->add_child($assignments);
416
417 $overrides->add_child($override);
418 $assignments->add_child($assignment);
419
420 // Define sources
421
422 $override->set_source_table('role_capabilities', array('contextid' => backup::VAR_CONTEXTID));
423
424 // Assignments only added if specified
425 if ($roleassignments) {
426 $assignment->set_source_table('role_assignments', array('contextid' => backup::VAR_CONTEXTID));
427 }
428
429 // Define id annotations
430 $override->annotate_ids('role', 'roleid');
431
432 $assignment->annotate_ids('role', 'roleid');
433
434 $assignment->annotate_ids('user', 'userid');
435
cb34c4cd
PS
436 //TODO: how do we annotate the itemid? the meaning depends on the content of component table (skodak)
437
77547b46
EL
438 return $roles;
439 }
440}
441
442/**
443 * structure step that will generate the roles.xml containing the
444 * list of roles used along the whole backup process. Just raw
445 * list of used roles from role table
446 */
447class backup_final_roles_structure_step extends backup_structure_step {
448
449 protected function define_structure() {
450
451 // Define elements
452
453 $rolesdef = new backup_nested_element('roles_definition');
454
455 $role = new backup_nested_element('role', array('id'), array(
456 'name', 'shortname', 'nameincourse', 'description',
457 'sortorder', 'archetype'));
458
459 // Build the tree
460
461 $rolesdef->add_child($role);
462
463 // Define sources
464
465 $role->set_source_sql("SELECT r.*, rn.name AS nameincourse
466 FROM {role} r
467 JOIN {backup_ids_temp} bi ON r.id = bi.itemid
468 LEFT JOIN {role_names} rn ON r.id = rn.roleid AND rn.contextid = ?
469 WHERE bi.backupid = ?
470 AND bi.itemname = 'rolefinal'", array(backup::VAR_CONTEXTID, backup::VAR_BACKUPID));
471
472 // Return main element (rolesdef)
473 return $rolesdef;
474 }
475}
476
477/**
478 * structure step that will generate the scales.xml containing the
479 * list of scales used along the whole backup process.
480 */
481class backup_final_scales_structure_step extends backup_structure_step {
482
483 protected function define_structure() {
484
485 // Define elements
486
487 $scalesdef = new backup_nested_element('scales_definition');
488
489 $scale = new backup_nested_element('scale', array('id'), array(
490 'courseid', 'userid', 'name', 'scale',
491 'description', 'descriptionformat', 'timemodified'));
492
493 // Build the tree
494
495 $scalesdef->add_child($scale);
496
497 // Define sources
498
499 $scale->set_source_sql("SELECT s.*
500 FROM {scale} s
501 JOIN {backup_ids_temp} bi ON s.id = bi.itemid
502 WHERE bi.backupid = ?
503 AND bi.itemname = 'scalefinal'", array(backup::VAR_BACKUPID));
504
3a1cccc6
EL
505 // Annotate scale files (they store files in system context, so pass it instead of default one)
506 $scale->annotate_files('grade', 'scale', 'id', get_context_instance(CONTEXT_SYSTEM)->id);
507
77547b46
EL
508 // Return main element (scalesdef)
509 return $scalesdef;
510 }
511}
512
513/**
514 * structure step that will generate the outcomes.xml containing the
515 * list of outcomes used along the whole backup process.
516 */
517class backup_final_outcomes_structure_step extends backup_structure_step {
518
519 protected function define_structure() {
520
521 // Define elements
522
523 $outcomesdef = new backup_nested_element('outcomes_definition');
524
525 $outcome = new backup_nested_element('outcome', array('id'), array(
526 'courseid', 'userid', 'shortname', 'fullname',
527 'scaleid', 'description', 'descriptionformat', 'timecreated',
528 'timemodified','usermodified'));
529
530 // Build the tree
531
532 $outcomesdef->add_child($outcome);
533
534 // Define sources
535
536 $outcome->set_source_sql("SELECT o.*
537 FROM {grade_outcomes} o
538 JOIN {backup_ids_temp} bi ON o.id = bi.itemid
539 WHERE bi.backupid = ?
540 AND bi.itemname = 'outcomefinal'", array(backup::VAR_BACKUPID));
541
c8730ff0
EL
542 // Annotate outcome files (they store files in system context, so pass it instead of default one)
543 $outcome->annotate_files('grade', 'outcome', 'id', get_context_instance(CONTEXT_SYSTEM)->id);
544
77547b46
EL
545 // Return main element (outcomesdef)
546 return $outcomesdef;
547 }
548}
549
550/**
551 * structure step in charge of constructing the filters.xml file for all the filters found
552 * in activity
553 */
554class backup_filters_structure_step extends backup_structure_step {
555
556 protected function define_structure() {
557
558 // Define each element separated
559
560 $filters = new backup_nested_element('filters');
561
562 $actives = new backup_nested_element('filter_actives');
563
564 $active = new backup_nested_element('filter_active', null, array('filter', 'active'));
565
566 $configs = new backup_nested_element('filter_configs');
567
568 $config = new backup_nested_element('filter_config', null, array('filter', 'name', 'value'));
569
570 // Build the tree
571
572 $filters->add_child($actives);
573 $filters->add_child($configs);
574
575 $actives->add_child($active);
576 $configs->add_child($config);
577
578 // Define sources
579
580 list($activearr, $configarr) = filter_get_all_local_settings($this->task->get_contextid());
581
582 $active->set_source_array($activearr);
583 $config->set_source_array($configarr);
584
585 // Return the root element (filters)
586 return $filters;
587 }
588}
589
590/**
591 * structure step in charge of constructing the comments.xml file for all the comments found
592 * in a given context
593 */
594class backup_comments_structure_step extends backup_structure_step {
595
596 protected function define_structure() {
597
598 // Define each element separated
599
600 $comments = new backup_nested_element('comments');
601
602 $comment = new backup_nested_element('comment', array('id'), array(
603 'commentarea', 'itemid', 'content', 'format',
604 'userid', 'timecreated'));
605
606 // Build the tree
607
608 $comments->add_child($comment);
609
610 // Define sources
611
612 $comment->set_source_table('comments', array('contextid' => backup::VAR_CONTEXTID));
613
614 // Define id annotations
615
616 $comment->annotate_ids('user', 'userid');
617
618 // Return the root element (comments)
619 return $comments;
620 }
621}
622
315f6d8e
AD
623/**
624 * structure step in charge of constructing the gradebook.xml file for all the gradebook config in the course
625 * NOTE: the backup of the grade items themselves is handled by backup_activity_grades_structure_step
626 */
627class backup_gradebook_structure_step extends backup_structure_step {
628
d39595cc
EL
629 /**
630 * We need to decide conditionally, based on dynamic information
631 * about the execution of this step. Only will be executed if all
632 * the module gradeitems have been already included in backup
633 */
634 protected function execute_condition() {
635 return backup_plan_dbops::require_gradebook_backup($this->get_courseid(), $this->get_backupid());
636 }
637
315f6d8e
AD
638 protected function define_structure() {
639
640 // are we including user info?
641 $userinfo = $this->get_setting_value('users');
642
643 $gradebook = new backup_nested_element('gradebook');
644
645 //grade_letters are done in backup_activity_grades_structure_step()
646
647 //calculated grade items
648 $grade_items = new backup_nested_element('grade_items');
649 $grade_item = new backup_nested_element('grade_item', array('id'), array(
650 'categoryid', 'itemname', 'itemtype', 'itemmodule',
651 'iteminstance', 'itemnumber', 'iteminfo', 'idnumber',
652 'calculation', 'gradetype', 'grademax', 'grademin',
653 'scaleid', 'outcomeid', 'gradepass', 'multfactor',
654 'plusfactor', 'aggregationcoef', 'sortorder', 'display',
655 'decimals', 'hidden', 'locked', 'locktime',
656 'needsupdate', 'timecreated', 'timemodified'));
657
658 $grade_grades = new backup_nested_element('grade_grades');
659 $grade_grade = new backup_nested_element('grade_grade', array('id'), array(
660 'userid', 'rawgrade', 'rawgrademax', 'rawgrademin',
661 'rawscaleid', 'usermodified', 'finalgrade', 'hidden',
662 'locked', 'locktime', 'exported', 'overridden',
663 'excluded', 'feedback', 'feedbackformat', 'information',
664 'informationformat', 'timecreated', 'timemodified'));
665
666 //grade_categories
667 $grade_categories = new backup_nested_element('grade_categories');
d39595cc
EL
668 $grade_category = new backup_nested_element('grade_category', null, array('courseid',
669 'parent', 'depth', 'path', 'fullname', 'aggregation', 'keephigh',
315f6d8e
AD
670 'dropload', 'aggregateonlygraded', 'aggregateoutcomes', 'aggregatesubcats',
671 'timecreated', 'timemodified'));
672
673 $letters = new backup_nested_element('grade_letters');
674 $letter = new backup_nested_element('grade_letter', 'id', array(
675 'lowerboundary', 'letter'));
676
677
678 // Build the tree
679
680 $gradebook->add_child($grade_items);
681 $grade_items->add_child($grade_item);
682 $grade_item->add_child($grade_grades);
683 $grade_grades->add_child($grade_grade);
684
685 //$grade_item->add_child($grade_scale);
686
687 $gradebook->add_child($grade_categories);
688 $grade_categories->add_child($grade_category);
689
690 $gradebook->add_child($letters);
691 $letters->add_child($letter);
692
693 // Define sources
694
be739b71
AD
695 //Include manual, category and the course grade item
696 $grade_items_sql ="SELECT * FROM {grade_items}
697 WHERE courseid = :courseid
698 AND (itemtype='manual' OR itemtype='course' OR itemtype='category')";
3f92c2fc 699 $grade_items_params = array('courseid'=>backup::VAR_COURSEID);
be739b71 700 $grade_item->set_source_sql($grade_items_sql, $grade_items_params);
315f6d8e
AD
701
702 if ($userinfo) {
703 $grade_grade->set_source_table('grade_grades', array('itemid' => backup::VAR_PARENTID));
704 }
705
706 $grade_category_sql = "SELECT gc.*, gi.sortorder
707 FROM {grade_categories} gc
708 JOIN {grade_items} gi ON (gi.iteminstance = gc.id)
709 WHERE gc.courseid = :courseid
710 AND (gi.itemtype='course' OR gi.itemtype='category')
711 ORDER BY gc.parent ASC";//need parent categories before their children
712 $grade_category_params = array('courseid'=>backup::VAR_COURSEID);
713 $grade_category->set_source_sql($grade_category_sql, $grade_category_params);
714
715 $letter->set_source_table('grade_letters', array('contextid' => backup::VAR_CONTEXTID));
716
76cfb124 717 // Annotations (both as final as far as they are going to be exported in next steps)
315f6d8e 718 $grade_item->annotate_ids('scalefinal', 'scaleid'); // Straight as scalefinal because it's > 0
76cfb124 719 $grade_item->annotate_ids('outcomefinal', 'outcomeid');
315f6d8e
AD
720
721 // Return the root element
722 return $gradebook;
723 }
724}
725
77547b46
EL
726/**
727 * structure step in charge if constructing the completion.xml file for all the users completion
728 * information in a given activity
729 */
730class backup_userscompletion_structure_step extends backup_structure_step {
731
732 protected function define_structure() {
733
734 // Define each element separated
735
736 $completions = new backup_nested_element('completions');
737
738 $completion = new backup_nested_element('completion', array('id'), array(
739 'userid', 'completionstate', 'viewed', 'timemodified'));
740
741 // Build the tree
742
743 $completions->add_child($completion);
744
745 // Define sources
746
747 $completion->set_source_table('course_modules_completion', array('coursemoduleid' => backup::VAR_MODID));
748
749 // Define id annotations
750
751 $completion->annotate_ids('user', 'userid');
752
753 // Return the root element (completions)
754 return $completions;
755 }
756}
757
758/**
759 * structure step in charge of constructing the main groups.xml file for all the groups and
760 * groupings information already annotated
761 */
762class backup_groups_structure_step extends backup_structure_step {
763
764 protected function define_structure() {
765
766 // To know if we are including users
767 $users = $this->get_setting_value('users');
768
769 // Define each element separated
770
771 $groups = new backup_nested_element('groups');
772
773 $group = new backup_nested_element('group', array('id'), array(
774 'name', 'description', 'descriptionformat', 'enrolmentkey',
775 'picture', 'hidepicture', 'timecreated', 'timemodified'));
776
777 $members = new backup_nested_element('group_members');
778
779 $member = new backup_nested_element('group_member', array('id'), array(
780 'userid', 'timeadded'));
781
782 $groupings = new backup_nested_element('groupings');
783
784 $grouping = new backup_nested_element('grouping', 'id', array(
785 'name', 'description', 'descriptionformat', 'configdata',
786 'timecreated', 'timemodified'));
787
788 $groupinggroups = new backup_nested_element('grouping_groups');
789
790 $groupinggroup = new backup_nested_element('grouping_group', array('id'), array(
791 'groupid', 'timeadded'));
792
793 // Build the tree
794
795 $groups->add_child($group);
796 $groups->add_child($groupings);
797
798 $group->add_child($members);
799 $members->add_child($member);
800
801 $groupings->add_child($grouping);
802 $grouping->add_child($groupinggroups);
803 $groupinggroups->add_child($groupinggroup);
804
805 // Define sources
806
807 $group->set_source_sql("
808 SELECT g.*
809 FROM {groups} g
810 JOIN {backup_ids_temp} bi ON g.id = bi.itemid
811 WHERE bi.backupid = ?
812 AND bi.itemname = 'groupfinal'", array(backup::VAR_BACKUPID));
813
814 // This only happens if we are including users
815 if ($users) {
816 $member->set_source_table('groups_members', array('groupid' => backup::VAR_PARENTID));
817 }
818
819 $grouping->set_source_sql("
820 SELECT g.*
821 FROM {groupings} g
822 JOIN {backup_ids_temp} bi ON g.id = bi.itemid
823 WHERE bi.backupid = ?
824 AND bi.itemname = 'groupingfinal'", array(backup::VAR_BACKUPID));
825
826 $groupinggroup->set_source_table('groupings_groups', array('groupingid' => backup::VAR_PARENTID));
827
828 // Define id annotations (as final)
829
830 $member->annotate_ids('userfinal', 'userid');
831
832 // Define file annotations
833
64f93798 834 $group->annotate_files('group', 'description', 'id');
78d47b30 835 $group->annotate_files('group', 'icon', 'id');
5cc70f32 836 $grouping->annotate_files('grouping', 'description', 'id');
77547b46
EL
837
838 // Return the root element (groups)
839 return $groups;
840 }
841}
842
843/**
844 * structure step in charge of constructing the main users.xml file for all the users already
845 * annotated (final). Includes custom profile fields, preferences, tags, role assignments and
846 * overrides.
847 */
848class backup_users_structure_step extends backup_structure_step {
849
850 protected function define_structure() {
851 global $CFG;
852
853 // To know if we are anonymizing users
854 $anonymize = $this->get_setting_value('anonymize');
855 // To know if we are including role assignments
856 $roleassignments = $this->get_setting_value('role_assignments');
857
858 // Define each element separated
859
860 $users = new backup_nested_element('users');
861
862 // Create the array of user fields by hand, as far as we have various bits to control
863 // anonymize option, password backup, mnethostid...
864
865 // First, the fields not needing anonymization nor special handling
866 $normalfields = array(
867 'confirmed', 'policyagreed', 'deleted',
868 'lang', 'theme', 'timezone', 'firstaccess',
482aac65 869 'lastaccess', 'lastlogin', 'currentlogin',
77547b46
EL
870 'mailformat', 'maildigest', 'maildisplay', 'htmleditor',
871 'ajax', 'autosubscribe', 'trackforums', 'timecreated',
872 'timemodified', 'trustbitmask', 'screenreader');
873
874 // Then, the fields potentially needing anonymization
875 $anonfields = array(
876 'username', 'idnumber', 'firstname', 'lastname',
482aac65
EL
877 'email', 'emailstop', 'icq', 'skype',
878 'yahoo', 'aim', 'msn', 'phone1',
879 'phone2', 'institution', 'department', 'address',
880 'city', 'country', 'lastip', 'picture',
c44d4aee 881 'url', 'description', 'descriptionformat', 'imagealt', 'auth');
77547b46
EL
882
883 // Add anonymized fields to $userfields with custom final element
884 foreach ($anonfields as $field) {
885 if ($anonymize) {
886 $userfields[] = new anonymizer_final_element($field);
887 } else {
888 $userfields[] = $field; // No anonymization, normally added
889 }
890 }
891
892 // mnethosturl requires special handling (custom final element)
893 $userfields[] = new mnethosturl_final_element('mnethosturl');
894
895 // password added conditionally
896 if (!empty($CFG->includeuserpasswordsinbackup)) {
897 $userfields[] = 'password';
898 }
899
900 // Merge all the fields
901 $userfields = array_merge($userfields, $normalfields);
902
903 $user = new backup_nested_element('user', array('id', 'contextid'), $userfields);
904
905 $customfields = new backup_nested_element('custom_fields');
906
907 $customfield = new backup_nested_element('custom_field', array('id'), array(
908 'field_name', 'field_type', 'field_data'));
909
910 $tags = new backup_nested_element('tags');
911
912 $tag = new backup_nested_element('tag', array('id'), array(
913 'name', 'rawname'));
914
915 $preferences = new backup_nested_element('preferences');
916
917 $preference = new backup_nested_element('preference', array('id'), array(
918 'name', 'value'));
919
920 $roles = new backup_nested_element('roles');
921
922 $overrides = new backup_nested_element('role_overrides');
923
924 $override = new backup_nested_element('override', array('id'), array(
925 'roleid', 'capability', 'permission', 'timemodified',
926 'modifierid'));
927
928 $assignments = new backup_nested_element('role_assignments');
929
930 $assignment = new backup_nested_element('assignment', array('id'), array(
df997f84 931 'roleid', 'userid', 'timemodified', 'modifierid', 'component', //TODO: MDL-22793 add itemid here
77547b46
EL
932 'sortorder'));
933
934 // Build the tree
935
936 $users->add_child($user);
937
938 $user->add_child($customfields);
939 $customfields->add_child($customfield);
940
941 $user->add_child($tags);
942 $tags->add_child($tag);
943
944 $user->add_child($preferences);
945 $preferences->add_child($preference);
946
947 $user->add_child($roles);
948
949 $roles->add_child($overrides);
950 $roles->add_child($assignments);
951
952 $overrides->add_child($override);
953 $assignments->add_child($assignment);
954
955 // Define sources
956
957 $user->set_source_sql('SELECT u.*, c.id AS contextid, m.wwwroot AS mnethosturl
958 FROM {user} u
959 JOIN {backup_ids_temp} bi ON bi.itemid = u.id
960 JOIN {context} c ON c.instanceid = u.id
961 LEFT JOIN {mnet_host} m ON m.id = u.mnethostid
962 WHERE bi.backupid = ?
963 AND bi.itemname = ?
964 AND c.contextlevel = ?', array(
c0bd6249
EL
965 backup_helper::is_sqlparam($this->get_backupid()),
966 backup_helper::is_sqlparam('userfinal'),
967 backup_helper::is_sqlparam(CONTEXT_USER)));
77547b46
EL
968
969 // All the rest on information is only added if we arent
970 // in an anonymized backup
971 if (!$anonymize) {
972 $customfield->set_source_sql('SELECT f.id, f.shortname, f.datatype, d.data
973 FROM {user_info_field} f
974 JOIN {user_info_data} d ON d.fieldid = f.id
975 WHERE d.userid = ?', array(backup::VAR_PARENTID));
976
977 $customfield->set_source_alias('shortname', 'field_name');
978 $customfield->set_source_alias('datatype', 'field_type');
979 $customfield->set_source_alias('data', 'field_data');
980
981 $tag->set_source_sql('SELECT t.id, t.name, t.rawname
982 FROM {tag} t
983 JOIN {tag_instance} ti ON ti.tagid = t.id
984 WHERE ti.itemtype = ?
985 AND ti.itemid = ?', array(
c0bd6249 986 backup_helper::is_sqlparam('user'),
77547b46
EL
987 backup::VAR_PARENTID));
988
989 $preference->set_source_table('user_preferences', array('userid' => backup::VAR_PARENTID));
990
991 $override->set_source_table('role_capabilities', array('contextid' => '/users/user/contextid'));
992
993 // Assignments only added if specified
994 if ($roleassignments) {
995 $assignment->set_source_table('role_assignments', array('contextid' => '/users/user/contextid'));
996 }
997
998 // Define id annotations (as final)
999 $override->annotate_ids('rolefinal', 'roleid');
1000 }
1001
1002 // Return root element (users)
1003 return $users;
1004 }
1005}
1006
1007/**
1008 * structure step in charge of constructing the block.xml file for one
39b5371c 1009 * given block (instance and positions). If the block has custom DB structure
77547b46
EL
1010 * that will go to a separate file (different step defined in block class)
1011 */
1012class backup_block_instance_structure_step extends backup_structure_step {
1013
1014 protected function define_structure() {
1015 global $DB;
1016
1017 // Define each element separated
1018
5f8354eb 1019 $block = new backup_nested_element('block', array('id', 'contextid', 'version'), array(
61243f3a
EL
1020 'blockname', 'parentcontextid', 'showinsubcontexts', 'pagetypepattern',
1021 'subpagepattern', 'defaultregion', 'defaultweight', 'configdata'));
77547b46
EL
1022
1023 $positions = new backup_nested_element('block_positions', null, array(
1024 'contextid', 'pagetype', 'subpage', 'visible',
1025 'region', 'weight'));
1026
1027 // Build the tree
1028
1029 $block->add_child($positions);
1030
1031 // Transform configdata information if needed (process links and friends)
1032 $blockrec = $DB->get_record('block_instances', array('id' => $this->task->get_blockid()));
1033 if ($attrstotransform = $this->task->get_configdata_encoded_attributes()) {
1034 $configdata = (array)unserialize(base64_decode($blockrec->configdata));
1035 foreach ($configdata as $attribute => $value) {
1036 if (in_array($attribute, $attrstotransform)) {
1037 $configdata[$attribute] = $this->contenttransformer->process($value);
1038 }
1039 }
1040 $blockrec->configdata = base64_encode(serialize((object)$configdata));
1041 }
5f8354eb 1042 $blockrec->contextid = $this->task->get_contextid();
77547b46
EL
1043 // Get the version of the block
1044 $blockrec->version = $DB->get_field('block', 'version', array('name' => $this->task->get_blockname()));
1045
1046 // Define sources
1047
1048 $block->set_source_array(array($blockrec));
1049
1050 $positions->set_source_table('block_positions', array('blockinstanceid' => backup::VAR_PARENTID));
1051
4a15bb76
EL
1052 // File anotations (for fileareas specified on each block)
1053 foreach ($this->task->get_fileareas() as $filearea) {
1054 $block->annotate_files('block_' . $this->task->get_blockname(), $filearea, null);
1055 }
1056
77547b46
EL
1057 // Return the root element (block)
1058 return $block;
1059 }
1060}
1061
1062/**
1063 * structure step in charge of constructing the logs.xml file for all the log records found
1064 * in activity
1065 */
1066class backup_activity_logs_structure_step extends backup_structure_step {
1067
1068 protected function define_structure() {
1069
1070 // Define each element separated
1071
1072 $logs = new backup_nested_element('logs');
1073
1074 $log = new backup_nested_element('log', array('id'), array(
1075 'time', 'userid', 'ip', 'module',
1076 'action', 'url', 'info'));
1077
1078 // Build the tree
1079
1080 $logs->add_child($log);
1081
1082 // Define sources
1083
1084 $log->set_source_table('log', array('cmid' => backup::VAR_MODID));
1085
1086 // Annotations
1087 // NOTE: We don't annotate users from logs as far as they MUST be
1088 // always annotated by the activity.
1089
1090 // Return the root element (logs)
1091
1092 return $logs;
1093 }
1094}
1095
1096/**
1097 * structure in charge of constructing the inforef.xml file for all the items we want
1098 * to have referenced there (users, roles, files...)
1099 */
1100class backup_inforef_structure_step extends backup_structure_step {
1101
1102 protected function define_structure() {
1103
482aac65
EL
1104 // Items we want to include in the inforef file.
1105 $items = backup_helper::get_inforef_itemnames();
77547b46
EL
1106
1107 // Build the tree
1108
1109 $inforef = new backup_nested_element('inforef');
1110
1111 // For each item, conditionally, if there are already records, build element
1112 foreach ($items as $itemname) {
1113 if (backup_structure_dbops::annotations_exist($this->get_backupid(), $itemname)) {
1114 $elementroot = new backup_nested_element($itemname . 'ref');
482aac65 1115 $element = new backup_nested_element($itemname, array(), array('id'));
77547b46
EL
1116 $inforef->add_child($elementroot);
1117 $elementroot->add_child($element);
1118 $element->set_source_sql("
1119 SELECT itemid AS id
1120 FROM {backup_ids_temp}
1121 WHERE backupid = ?
1122 AND itemname = ?",
c0bd6249 1123 array(backup::VAR_BACKUPID, backup_helper::is_sqlparam($itemname)));
77547b46
EL
1124 }
1125 }
1126
1127 // We don't annotate anything there, but rely in the next step
1128 // (move_inforef_annotations_to_final) that will change all the
1129 // already saved 'inforref' entries to their 'final' annotations.
1130 return $inforef;
1131 }
1132}
1133
1134/**
1135 * This step will get all the annotations already processed to inforef.xml file and
1136 * transform them into 'final' annotations.
1137 */
1138class move_inforef_annotations_to_final extends backup_execution_step {
1139
1140 protected function define_execution() {
1141
482aac65
EL
1142 // Items we want to include in the inforef file
1143 $items = backup_helper::get_inforef_itemnames();
77547b46
EL
1144 foreach ($items as $itemname) {
1145 // Delegate to dbops
1146 backup_structure_dbops::move_annotations_to_final($this->get_backupid(), $itemname);
1147 }
1148 }
1149}
1150
1151/**
1152 * structure in charge of constructing the files.xml file with all the
1153 * annotated (final) files along the process. At, the same time, and
1154 * using one specialised nested_element, will copy them form moodle storage
1155 * to backup storage
1156 */
1157class backup_final_files_structure_step extends backup_structure_step {
1158
1159 protected function define_structure() {
1160
1161 // Define elements
1162
1163 $files = new backup_nested_element('files');
1164
1165 $file = new file_nested_element('file', array('id'), array(
64f93798 1166 'contenthash', 'contextid', 'component', 'filearea', 'itemid',
77547b46
EL
1167 'filepath', 'filename', 'userid', 'filesize',
1168 'mimetype', 'status', 'timecreated', 'timemodified',
1fd3ea43 1169 'source', 'author', 'license', 'sortorder'));
77547b46
EL
1170
1171 // Build the tree
1172
1173 $files->add_child($file);
1174
1175 // Define sources
1176
1177 $file->set_source_sql("SELECT f.*
1178 FROM {files} f
1179 JOIN {backup_ids_temp} bi ON f.id = bi.itemid
1180 WHERE bi.backupid = ?
1181 AND bi.itemname = 'filefinal'", array(backup::VAR_BACKUPID));
1182
1183 return $files;
1184 }
1185}
1186
1187/**
1188 * Structure step in charge of creating the main moodle_backup.xml file
1189 * where all the information related to the backup, settings, license and
1190 * other information needed on restore is added*/
1191class backup_main_structure_step extends backup_structure_step {
1192
1193 protected function define_structure() {
1194
1195 global $CFG;
1196
1197 $info = array();
1198
1199 $info['name'] = $this->get_setting_value('filename');
1200 $info['moodle_version'] = $CFG->version;
1201 $info['moodle_release'] = $CFG->release;
1202 $info['backup_version'] = $CFG->backup_version;
1203 $info['backup_release'] = $CFG->backup_release;
1204 $info['backup_date'] = time();
1205 $info['backup_uniqueid']= $this->get_backupid();
c3ea499d 1206 $info['mnet_remoteusers']=backup_controller_dbops::backup_includes_mnet_remote_users($this->get_backupid());
77547b46 1207 $info['original_wwwroot']=$CFG->wwwroot;
482aac65 1208 $info['original_site_identifier_hash'] = md5(get_site_identifier());
77547b46 1209 $info['original_course_id'] = $this->get_courseid();
560811a9
EL
1210 $originalcourseinfo = backup_controller_dbops::backup_get_original_course_info($this->get_courseid());
1211 $info['original_course_fullname'] = $originalcourseinfo->fullname;
1212 $info['original_course_shortname'] = $originalcourseinfo->shortname;
1213 $info['original_course_startdate'] = $originalcourseinfo->startdate;
76cfb124 1214 $info['original_course_contextid'] = get_context_instance(CONTEXT_COURSE, $this->get_courseid())->id;
3a1cccc6 1215 $info['original_system_contextid'] = get_context_instance(CONTEXT_SYSTEM)->id;
77547b46
EL
1216
1217 // Get more information from controller
1218 list($dinfo, $cinfo, $sinfo) = backup_controller_dbops::get_moodle_backup_information($this->get_backupid());
1219
1220 // Define elements
1221
1222 $moodle_backup = new backup_nested_element('moodle_backup');
1223
1224 $information = new backup_nested_element('information', null, array(
1225 'name', 'moodle_version', 'moodle_release', 'backup_version',
c3ea499d 1226 'backup_release', 'backup_date', 'mnet_remoteusers', 'original_wwwroot',
560811a9
EL
1227 'original_site_identifier_hash', 'original_course_id',
1228 'original_course_fullname', 'original_course_shortname', 'original_course_startdate',
1229 'original_course_contextid', 'original_system_contextid'));
77547b46
EL
1230
1231 $details = new backup_nested_element('details');
1232
1233 $detail = new backup_nested_element('detail', array('backup_id'), array(
1234 'type', 'format', 'interactive', 'mode',
1235 'execution', 'executiontime'));
1236
1237 $contents = new backup_nested_element('contents');
1238
1239 $activities = new backup_nested_element('activities');
1240
1241 $activity = new backup_nested_element('activity', null, array(
1242 'moduleid', 'sectionid', 'modulename', 'title',
1243 'directory'));
1244
1245 $sections = new backup_nested_element('sections');
1246
1247 $section = new backup_nested_element('section', null, array(
1248 'sectionid', 'title', 'directory'));
1249
1250 $course = new backup_nested_element('course', null, array(
1251 'courseid', 'title', 'directory'));
1252
1253 $settings = new backup_nested_element('settings');
1254
1255 $setting = new backup_nested_element('setting', null, array(
d12fd69b 1256 'level', 'section', 'activity', 'name', 'value'));
77547b46
EL
1257
1258 // Build the tree
1259
1260 $moodle_backup->add_child($information);
1261
1262 $information->add_child($details);
1263 $details->add_child($detail);
1264
1265 $information->add_child($contents);
1266 if (!empty($cinfo['activities'])) {
1267 $contents->add_child($activities);
1268 $activities->add_child($activity);
1269 }
1270 if (!empty($cinfo['sections'])) {
1271 $contents->add_child($sections);
1272 $sections->add_child($section);
1273 }
1274 if (!empty($cinfo['course'])) {
1275 $contents->add_child($course);
1276 }
1277
1278 $information->add_child($settings);
1279 $settings->add_child($setting);
1280
1281
1282 // Set the sources
1283
1284 $information->set_source_array(array((object)$info));
1285
1286 $detail->set_source_array($dinfo);
1287
1288 $activity->set_source_array($cinfo['activities']);
1289
1290 $section->set_source_array($cinfo['sections']);
1291
1292 $course->set_source_array($cinfo['course']);
1293
1294 $setting->set_source_array($sinfo);
1295
1296 // Prepare some information to be sent to main moodle_backup.xml file
1297 return $moodle_backup;
1298 }
1299
1300}
1301
ce937f99
EL
1302/**
1303 * Execution step that will generate the final zip file with all the contents
1304 */
1305class backup_zip_contents extends backup_execution_step {
1306
1307 protected function define_execution() {
1308
1309 // Get basepath
1310 $basepath = $this->get_basepath();
1311
1312 // Get the list of files in directory
1313 $filestemp = get_directory_list($basepath, '', false, true, true);
1314 $files = array();
1315 foreach ($filestemp as $file) { // Add zip paths and fs paths to all them
1316 $files[$file] = $basepath . '/' . $file;
1317 }
1318
1319 // Add the log file if exists
1320 $logfilepath = $basepath . '.log';
1321 if (file_exists($logfilepath)) {
1322 $files['moodle_backup.log'] = $logfilepath;
1323 }
1324
9eeaea5f
EL
1325 // Calculate the zip fullpath (in OS temp area it's always backup.zip)
1326 $zipfile = $basepath . '/backup.zip';
ce937f99
EL
1327
1328 // Get the zip packer
1329 $zippacker = get_file_packer('application/zip');
1330
1331 // Zip files
1332 $zippacker->archive_to_pathname($files, $zipfile);
1333 }
1334}
1335
1336/**
1337 * This step will send the generated backup file to its final destination
1338 */
1339class backup_store_backup_file extends backup_execution_step {
1340
1341 protected function define_execution() {
1342
1343 // Get basepath
1344 $basepath = $this->get_basepath();
1345
9eeaea5f
EL
1346 // Calculate the zip fullpath (in OS temp area it's always backup.zip)
1347 $zipfile = $basepath . '/backup.zip';
ce937f99
EL
1348
1349 // Perform storage and return it (TODO: shouldn't be array but proper result object)
1350 return array('backup_destination' => backup_helper::store_backup_file($this->get_backupid(), $zipfile));
1351 }
1352}
1353
1354
77547b46
EL
1355/**
1356 * This step will search for all the activity (not calculations, categories nor aggregations) grade items
1357 * and put them to the backup_ids tables, to be used later as base to backup them
1358 */
1359class backup_activity_grade_items_to_ids extends backup_execution_step {
1360
1361 protected function define_execution() {
1362
1363 // Fetch all activity grade items
1364 if ($items = grade_item::fetch_all(array(
1365 'itemtype' => 'mod', 'itemmodule' => $this->task->get_modulename(),
1366 'iteminstance' => $this->task->get_activityid(), 'courseid' => $this->task->get_courseid()))) {
1367 // Annotate them in backup_ids
1368 foreach ($items as $item) {
1369 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'grade_item', $item->id);
1370 }
1371 }
1372 }
1373}
1374
1375/**
1376 * This step will annotate all the groups belonging to already annotated groupings
1377 */
1378class backup_annotate_groups_from_groupings extends backup_execution_step {
1379
1380 protected function define_execution() {
1381 global $DB;
1382
1383 // Fetch all the annotated groupings
1384 if ($groupings = $DB->get_records('backup_ids_temp', array(
1385 'backupid' => $this->get_backupid(), 'itemname' => 'grouping'))) {
1386 foreach ($groupings as $grouping) {
1387 if ($groups = $DB->get_records('groupings_groups', array(
1388 'groupingid' => $grouping->itemid))) {
1389 foreach ($groups as $group) {
1390 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'group', $group->groupid);
1391 }
1392 }
1393 }
1394 }
1395 }
1396}
1397
1398/**
1399 * This step will annotate all the scales belonging to already annotated outcomes
1400 */
1401class backup_annotate_scales_from_outcomes extends backup_execution_step {
1402
1403 protected function define_execution() {
1404 global $DB;
1405
1406 // Fetch all the annotated outcomes
1407 if ($outcomes = $DB->get_records('backup_ids_temp', array(
1408 'backupid' => $this->get_backupid(), 'itemname' => 'outcome'))) {
1409 foreach ($outcomes as $outcome) {
1410 if ($scale = $DB->get_record('grade_outcomes', array(
1411 'id' => $outcome->itemid))) {
1412 // Annotate as scalefinal because it's > 0
1413 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'scalefinal', $scale->scaleid);
1414 }
1415 }
1416 }
1417 }
1418}
1419
1420/**
76cfb124 1421 * This step will generate all the file annotations for the already
39b5371c 1422 * annotated (final) users. Need to do this here because each user
77547b46
EL
1423 * has its own context and structure tasks only are able to handle
1424 * one context. Also, this step will guarantee that every user has
1425 * its context created (req for other steps)
1426 */
1427class backup_annotate_all_user_files extends backup_execution_step {
1428
1429 protected function define_execution() {
1430 global $DB;
1431
1432 // List of fileareas we are going to annotate
76cfb124
EL
1433 $fileareas = array('profile', 'icon');
1434
1435 if ($this->get_setting_value('user_files')) { // private files only if enabled in settings
1436 $fileareas[] = 'private';
1437 }
77547b46
EL
1438
1439 // Fetch all annotated (final) users
1440 $rs = $DB->get_recordset('backup_ids_temp', array(
1441 'backupid' => $this->get_backupid(), 'itemname' => 'userfinal'));
1442 foreach ($rs as $record) {
1443 $userid = $record->itemid;
1444 $userctxid = get_context_instance(CONTEXT_USER, $userid)->id;
1445 // Proceed with every user filearea
1446 foreach ($fileareas as $filearea) {
78d47b30 1447 // We don't need to specify itemid ($userid - 5th param) as far as by
77547b46 1448 // context we can get all the associated files. See MDL-22092
64f93798 1449 backup_structure_dbops::annotate_files($this->get_backupid(), $userctxid, 'user', $filearea, null);
77547b46
EL
1450 }
1451 }
1452 $rs->close();
1453 }
1454}
1455
1456/**
1457 * structure step in charge of constructing the grades.xml file for all the grade items
1458 * and letters related to one activity
1459 */
1460class backup_activity_grades_structure_step extends backup_structure_step {
1461
1462 protected function define_structure() {
1463
1464 // To know if we are including userinfo
1465 $userinfo = $this->get_setting_value('userinfo');
1466
1467 // Define each element separated
1468
1469 $book = new backup_nested_element('activity_gradebook');
1470
1471 $items = new backup_nested_element('grade_items');
1472
1473 $item = new backup_nested_element('grade_item', array('id'), array(
1474 'categoryid', 'itemname', 'itemtype', 'itemmodule',
1475 'iteminstance', 'itemnumber', 'iteminfo', 'idnumber',
1476 'calculation', 'gradetype', 'grademax', 'grademin',
1477 'scaleid', 'outcomeid', 'gradepass', 'multfactor',
1478 'plusfactor', 'aggregationcoef', 'sortorder', 'display',
1479 'decimals', 'hidden', 'locked', 'locktime',
1480 'needsupdate', 'timecreated', 'timemodified'));
1481
1482 $grades = new backup_nested_element('grade_grades');
1483
1484 $grade = new backup_nested_element('grade_grade', array('id'), array(
1485 'userid', 'rawgrade', 'rawgrademax', 'rawgrademin',
1486 'rawscaleid', 'usermodified', 'finalgrade', 'hidden',
1487 'locked', 'locktime', 'exported', 'overridden',
1488 'excluded', 'feedback', 'feedbackformat', 'information',
1489 'informationformat', 'timecreated', 'timemodified'));
1490
1491 $letters = new backup_nested_element('grade_letters');
1492
1493 $letter = new backup_nested_element('grade_letter', 'id', array(
1494 'lowerboundary', 'letter'));
1495
1496 // Build the tree
1497
1498 $book->add_child($items);
1499 $items->add_child($item);
1500
1501 $item->add_child($grades);
1502 $grades->add_child($grade);
1503
1504 $book->add_child($letters);
1505 $letters->add_child($letter);
1506
1507 // Define sources
1508
315f6d8e
AD
1509 $item->set_source_sql("SELECT gi.*
1510 FROM {grade_items} gi
1511 JOIN {backup_ids_temp} bi ON gi.id = bi.itemid
1512 WHERE bi.backupid = ?
1513 AND bi.itemname = 'grade_item'", array(backup::VAR_BACKUPID));
77547b46
EL
1514
1515 // This only happens if we are including user info
1516 if ($userinfo) {
1517 $grade->set_source_table('grade_grades', array('itemid' => backup::VAR_PARENTID));
1518 }
1519
1520 $letter->set_source_table('grade_letters', array('contextid' => backup::VAR_CONTEXTID));
1521
1522 // Annotations
1523
1524 $item->annotate_ids('scalefinal', 'scaleid'); // Straight as scalefinal because it's > 0
1525 $item->annotate_ids('outcome', 'outcomeid');
1526
1527 $grade->annotate_ids('user', 'userid');
1528 $grade->annotate_ids('user', 'usermodified');
1529
1530 // Return the root element (book)
1531
1532 return $book;
1533 }
1534}