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