backup MDL-22139 changed gradebook backup to include category and course grade items
[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',
272 'enablecompletion'));
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
284 $module = new backup_nested_element('module', array('modulename'));
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
505 // Return main element (scalesdef)
506 return $scalesdef;
507 }
508}
509
510/**
511 * structure step that will generate the outcomes.xml containing the
512 * list of outcomes used along the whole backup process.
513 */
514class backup_final_outcomes_structure_step extends backup_structure_step {
515
516 protected function define_structure() {
517
518 // Define elements
519
520 $outcomesdef = new backup_nested_element('outcomes_definition');
521
522 $outcome = new backup_nested_element('outcome', array('id'), array(
523 'courseid', 'userid', 'shortname', 'fullname',
524 'scaleid', 'description', 'descriptionformat', 'timecreated',
525 'timemodified','usermodified'));
526
527 // Build the tree
528
529 $outcomesdef->add_child($outcome);
530
531 // Define sources
532
533 $outcome->set_source_sql("SELECT o.*
534 FROM {grade_outcomes} o
535 JOIN {backup_ids_temp} bi ON o.id = bi.itemid
536 WHERE bi.backupid = ?
537 AND bi.itemname = 'outcomefinal'", array(backup::VAR_BACKUPID));
538
539 // Return main element (outcomesdef)
540 return $outcomesdef;
541 }
542}
543
544/**
545 * structure step in charge of constructing the filters.xml file for all the filters found
546 * in activity
547 */
548class backup_filters_structure_step extends backup_structure_step {
549
550 protected function define_structure() {
551
552 // Define each element separated
553
554 $filters = new backup_nested_element('filters');
555
556 $actives = new backup_nested_element('filter_actives');
557
558 $active = new backup_nested_element('filter_active', null, array('filter', 'active'));
559
560 $configs = new backup_nested_element('filter_configs');
561
562 $config = new backup_nested_element('filter_config', null, array('filter', 'name', 'value'));
563
564 // Build the tree
565
566 $filters->add_child($actives);
567 $filters->add_child($configs);
568
569 $actives->add_child($active);
570 $configs->add_child($config);
571
572 // Define sources
573
574 list($activearr, $configarr) = filter_get_all_local_settings($this->task->get_contextid());
575
576 $active->set_source_array($activearr);
577 $config->set_source_array($configarr);
578
579 // Return the root element (filters)
580 return $filters;
581 }
582}
583
584/**
585 * structure step in charge of constructing the comments.xml file for all the comments found
586 * in a given context
587 */
588class backup_comments_structure_step extends backup_structure_step {
589
590 protected function define_structure() {
591
592 // Define each element separated
593
594 $comments = new backup_nested_element('comments');
595
596 $comment = new backup_nested_element('comment', array('id'), array(
597 'commentarea', 'itemid', 'content', 'format',
598 'userid', 'timecreated'));
599
600 // Build the tree
601
602 $comments->add_child($comment);
603
604 // Define sources
605
606 $comment->set_source_table('comments', array('contextid' => backup::VAR_CONTEXTID));
607
608 // Define id annotations
609
610 $comment->annotate_ids('user', 'userid');
611
612 // Return the root element (comments)
613 return $comments;
614 }
615}
616
315f6d8e
AD
617/**
618 * structure step in charge of constructing the gradebook.xml file for all the gradebook config in the course
619 * NOTE: the backup of the grade items themselves is handled by backup_activity_grades_structure_step
620 */
621class backup_gradebook_structure_step extends backup_structure_step {
622
d39595cc
EL
623 /**
624 * We need to decide conditionally, based on dynamic information
625 * about the execution of this step. Only will be executed if all
626 * the module gradeitems have been already included in backup
627 */
628 protected function execute_condition() {
629 return backup_plan_dbops::require_gradebook_backup($this->get_courseid(), $this->get_backupid());
630 }
631
315f6d8e
AD
632 protected function define_structure() {
633
634 // are we including user info?
635 $userinfo = $this->get_setting_value('users');
636
637 $gradebook = new backup_nested_element('gradebook');
638
639 //grade_letters are done in backup_activity_grades_structure_step()
640
641 //calculated grade items
642 $grade_items = new backup_nested_element('grade_items');
643 $grade_item = new backup_nested_element('grade_item', array('id'), array(
644 'categoryid', 'itemname', 'itemtype', 'itemmodule',
645 'iteminstance', 'itemnumber', 'iteminfo', 'idnumber',
646 'calculation', 'gradetype', 'grademax', 'grademin',
647 'scaleid', 'outcomeid', 'gradepass', 'multfactor',
648 'plusfactor', 'aggregationcoef', 'sortorder', 'display',
649 'decimals', 'hidden', 'locked', 'locktime',
650 'needsupdate', 'timecreated', 'timemodified'));
651
652 $grade_grades = new backup_nested_element('grade_grades');
653 $grade_grade = new backup_nested_element('grade_grade', array('id'), array(
654 'userid', 'rawgrade', 'rawgrademax', 'rawgrademin',
655 'rawscaleid', 'usermodified', 'finalgrade', 'hidden',
656 'locked', 'locktime', 'exported', 'overridden',
657 'excluded', 'feedback', 'feedbackformat', 'information',
658 'informationformat', 'timecreated', 'timemodified'));
659
660 //grade_categories
661 $grade_categories = new backup_nested_element('grade_categories');
d39595cc
EL
662 $grade_category = new backup_nested_element('grade_category', null, array('courseid',
663 'parent', 'depth', 'path', 'fullname', 'aggregation', 'keephigh',
315f6d8e
AD
664 'dropload', 'aggregateonlygraded', 'aggregateoutcomes', 'aggregatesubcats',
665 'timecreated', 'timemodified'));
666
667 $letters = new backup_nested_element('grade_letters');
668 $letter = new backup_nested_element('grade_letter', 'id', array(
669 'lowerboundary', 'letter'));
670
671
672 // Build the tree
673
674 $gradebook->add_child($grade_items);
675 $grade_items->add_child($grade_item);
676 $grade_item->add_child($grade_grades);
677 $grade_grades->add_child($grade_grade);
678
679 //$grade_item->add_child($grade_scale);
680
681 $gradebook->add_child($grade_categories);
682 $grade_categories->add_child($grade_category);
683
684 $gradebook->add_child($letters);
685 $letters->add_child($letter);
686
687 // Define sources
688
be739b71
AD
689 //Include manual, category and the course grade item
690 $grade_items_sql ="SELECT * FROM {grade_items}
691 WHERE courseid = :courseid
692 AND (itemtype='manual' OR itemtype='course' OR itemtype='category')";
693 $grade_items_params = array('courseid'=>$this->get_courseid());
694 $grade_item->set_source_sql($grade_items_sql, $grade_items_params);
315f6d8e
AD
695
696 if ($userinfo) {
697 $grade_grade->set_source_table('grade_grades', array('itemid' => backup::VAR_PARENTID));
698 }
699
700 $grade_category_sql = "SELECT gc.*, gi.sortorder
701 FROM {grade_categories} gc
702 JOIN {grade_items} gi ON (gi.iteminstance = gc.id)
703 WHERE gc.courseid = :courseid
704 AND (gi.itemtype='course' OR gi.itemtype='category')
705 ORDER BY gc.parent ASC";//need parent categories before their children
706 $grade_category_params = array('courseid'=>backup::VAR_COURSEID);
707 $grade_category->set_source_sql($grade_category_sql, $grade_category_params);
708
709 $letter->set_source_table('grade_letters', array('contextid' => backup::VAR_CONTEXTID));
710
711 // Annotations
712 $grade_item->annotate_ids('scalefinal', 'scaleid'); // Straight as scalefinal because it's > 0
713 $grade_item->annotate_ids('outcome', 'outcomeid');
714
715 // Return the root element
716 return $gradebook;
717 }
718}
719
77547b46
EL
720/**
721 * structure step in charge if constructing the completion.xml file for all the users completion
722 * information in a given activity
723 */
724class backup_userscompletion_structure_step extends backup_structure_step {
725
726 protected function define_structure() {
727
728 // Define each element separated
729
730 $completions = new backup_nested_element('completions');
731
732 $completion = new backup_nested_element('completion', array('id'), array(
733 'userid', 'completionstate', 'viewed', 'timemodified'));
734
735 // Build the tree
736
737 $completions->add_child($completion);
738
739 // Define sources
740
741 $completion->set_source_table('course_modules_completion', array('coursemoduleid' => backup::VAR_MODID));
742
743 // Define id annotations
744
745 $completion->annotate_ids('user', 'userid');
746
747 // Return the root element (completions)
748 return $completions;
749 }
750}
751
752/**
753 * structure step in charge of constructing the main groups.xml file for all the groups and
754 * groupings information already annotated
755 */
756class backup_groups_structure_step extends backup_structure_step {
757
758 protected function define_structure() {
759
760 // To know if we are including users
761 $users = $this->get_setting_value('users');
762
763 // Define each element separated
764
765 $groups = new backup_nested_element('groups');
766
767 $group = new backup_nested_element('group', array('id'), array(
768 'name', 'description', 'descriptionformat', 'enrolmentkey',
769 'picture', 'hidepicture', 'timecreated', 'timemodified'));
770
771 $members = new backup_nested_element('group_members');
772
773 $member = new backup_nested_element('group_member', array('id'), array(
774 'userid', 'timeadded'));
775
776 $groupings = new backup_nested_element('groupings');
777
778 $grouping = new backup_nested_element('grouping', 'id', array(
779 'name', 'description', 'descriptionformat', 'configdata',
780 'timecreated', 'timemodified'));
781
782 $groupinggroups = new backup_nested_element('grouping_groups');
783
784 $groupinggroup = new backup_nested_element('grouping_group', array('id'), array(
785 'groupid', 'timeadded'));
786
787 // Build the tree
788
789 $groups->add_child($group);
790 $groups->add_child($groupings);
791
792 $group->add_child($members);
793 $members->add_child($member);
794
795 $groupings->add_child($grouping);
796 $grouping->add_child($groupinggroups);
797 $groupinggroups->add_child($groupinggroup);
798
799 // Define sources
800
801 $group->set_source_sql("
802 SELECT g.*
803 FROM {groups} g
804 JOIN {backup_ids_temp} bi ON g.id = bi.itemid
805 WHERE bi.backupid = ?
806 AND bi.itemname = 'groupfinal'", array(backup::VAR_BACKUPID));
807
808 // This only happens if we are including users
809 if ($users) {
810 $member->set_source_table('groups_members', array('groupid' => backup::VAR_PARENTID));
811 }
812
813 $grouping->set_source_sql("
814 SELECT g.*
815 FROM {groupings} g
816 JOIN {backup_ids_temp} bi ON g.id = bi.itemid
817 WHERE bi.backupid = ?
818 AND bi.itemname = 'groupingfinal'", array(backup::VAR_BACKUPID));
819
820 $groupinggroup->set_source_table('groupings_groups', array('groupingid' => backup::VAR_PARENTID));
821
822 // Define id annotations (as final)
823
824 $member->annotate_ids('userfinal', 'userid');
825
826 // Define file annotations
827
64f93798 828 $group->annotate_files('group', 'description', 'id');
78d47b30 829 $group->annotate_files('group', 'icon', 'id');
77547b46
EL
830
831 // Return the root element (groups)
832 return $groups;
833 }
834}
835
836/**
837 * structure step in charge of constructing the main users.xml file for all the users already
838 * annotated (final). Includes custom profile fields, preferences, tags, role assignments and
839 * overrides.
840 */
841class backup_users_structure_step extends backup_structure_step {
842
843 protected function define_structure() {
844 global $CFG;
845
846 // To know if we are anonymizing users
847 $anonymize = $this->get_setting_value('anonymize');
848 // To know if we are including role assignments
849 $roleassignments = $this->get_setting_value('role_assignments');
850
851 // Define each element separated
852
853 $users = new backup_nested_element('users');
854
855 // Create the array of user fields by hand, as far as we have various bits to control
856 // anonymize option, password backup, mnethostid...
857
858 // First, the fields not needing anonymization nor special handling
859 $normalfields = array(
860 'confirmed', 'policyagreed', 'deleted',
861 'lang', 'theme', 'timezone', 'firstaccess',
862 'lastaccess', 'lastlogin', 'currentlogin', 'secret',
863 'mailformat', 'maildigest', 'maildisplay', 'htmleditor',
864 'ajax', 'autosubscribe', 'trackforums', 'timecreated',
865 'timemodified', 'trustbitmask', 'screenreader');
866
867 // Then, the fields potentially needing anonymization
868 $anonfields = array(
869 'username', 'idnumber', 'firstname', 'lastname',
870 'email', 'emailstop', 'lastip', 'picture',
871 'url', 'description', 'description_format', 'imagealt', 'auth');
872
873 // Add anonymized fields to $userfields with custom final element
874 foreach ($anonfields as $field) {
875 if ($anonymize) {
876 $userfields[] = new anonymizer_final_element($field);
877 } else {
878 $userfields[] = $field; // No anonymization, normally added
879 }
880 }
881
882 // mnethosturl requires special handling (custom final element)
883 $userfields[] = new mnethosturl_final_element('mnethosturl');
884
885 // password added conditionally
886 if (!empty($CFG->includeuserpasswordsinbackup)) {
887 $userfields[] = 'password';
888 }
889
890 // Merge all the fields
891 $userfields = array_merge($userfields, $normalfields);
892
893 $user = new backup_nested_element('user', array('id', 'contextid'), $userfields);
894
895 $customfields = new backup_nested_element('custom_fields');
896
897 $customfield = new backup_nested_element('custom_field', array('id'), array(
898 'field_name', 'field_type', 'field_data'));
899
900 $tags = new backup_nested_element('tags');
901
902 $tag = new backup_nested_element('tag', array('id'), array(
903 'name', 'rawname'));
904
905 $preferences = new backup_nested_element('preferences');
906
907 $preference = new backup_nested_element('preference', array('id'), array(
908 'name', 'value'));
909
910 $roles = new backup_nested_element('roles');
911
912 $overrides = new backup_nested_element('role_overrides');
913
914 $override = new backup_nested_element('override', array('id'), array(
915 'roleid', 'capability', 'permission', 'timemodified',
916 'modifierid'));
917
918 $assignments = new backup_nested_element('role_assignments');
919
920 $assignment = new backup_nested_element('assignment', array('id'), array(
df997f84 921 'roleid', 'userid', 'timemodified', 'modifierid', 'component', //TODO: MDL-22793 add itemid here
77547b46
EL
922 'sortorder'));
923
924 // Build the tree
925
926 $users->add_child($user);
927
928 $user->add_child($customfields);
929 $customfields->add_child($customfield);
930
931 $user->add_child($tags);
932 $tags->add_child($tag);
933
934 $user->add_child($preferences);
935 $preferences->add_child($preference);
936
937 $user->add_child($roles);
938
939 $roles->add_child($overrides);
940 $roles->add_child($assignments);
941
942 $overrides->add_child($override);
943 $assignments->add_child($assignment);
944
945 // Define sources
946
947 $user->set_source_sql('SELECT u.*, c.id AS contextid, m.wwwroot AS mnethosturl
948 FROM {user} u
949 JOIN {backup_ids_temp} bi ON bi.itemid = u.id
950 JOIN {context} c ON c.instanceid = u.id
951 LEFT JOIN {mnet_host} m ON m.id = u.mnethostid
952 WHERE bi.backupid = ?
953 AND bi.itemname = ?
954 AND c.contextlevel = ?', array(
c0bd6249
EL
955 backup_helper::is_sqlparam($this->get_backupid()),
956 backup_helper::is_sqlparam('userfinal'),
957 backup_helper::is_sqlparam(CONTEXT_USER)));
77547b46
EL
958
959 // All the rest on information is only added if we arent
960 // in an anonymized backup
961 if (!$anonymize) {
962 $customfield->set_source_sql('SELECT f.id, f.shortname, f.datatype, d.data
963 FROM {user_info_field} f
964 JOIN {user_info_data} d ON d.fieldid = f.id
965 WHERE d.userid = ?', array(backup::VAR_PARENTID));
966
967 $customfield->set_source_alias('shortname', 'field_name');
968 $customfield->set_source_alias('datatype', 'field_type');
969 $customfield->set_source_alias('data', 'field_data');
970
971 $tag->set_source_sql('SELECT t.id, t.name, t.rawname
972 FROM {tag} t
973 JOIN {tag_instance} ti ON ti.tagid = t.id
974 WHERE ti.itemtype = ?
975 AND ti.itemid = ?', array(
c0bd6249 976 backup_helper::is_sqlparam('user'),
77547b46
EL
977 backup::VAR_PARENTID));
978
979 $preference->set_source_table('user_preferences', array('userid' => backup::VAR_PARENTID));
980
981 $override->set_source_table('role_capabilities', array('contextid' => '/users/user/contextid'));
982
983 // Assignments only added if specified
984 if ($roleassignments) {
985 $assignment->set_source_table('role_assignments', array('contextid' => '/users/user/contextid'));
986 }
987
988 // Define id annotations (as final)
989 $override->annotate_ids('rolefinal', 'roleid');
990 }
991
992 // Return root element (users)
993 return $users;
994 }
995}
996
997/**
998 * structure step in charge of constructing the block.xml file for one
39b5371c 999 * given block (instance and positions). If the block has custom DB structure
77547b46
EL
1000 * that will go to a separate file (different step defined in block class)
1001 */
1002class backup_block_instance_structure_step extends backup_structure_step {
1003
1004 protected function define_structure() {
1005 global $DB;
1006
1007 // Define each element separated
1008
5f8354eb 1009 $block = new backup_nested_element('block', array('id', 'contextid', 'version'), array(
61243f3a
EL
1010 'blockname', 'parentcontextid', 'showinsubcontexts', 'pagetypepattern',
1011 'subpagepattern', 'defaultregion', 'defaultweight', 'configdata'));
77547b46
EL
1012
1013 $positions = new backup_nested_element('block_positions', null, array(
1014 'contextid', 'pagetype', 'subpage', 'visible',
1015 'region', 'weight'));
1016
1017 // Build the tree
1018
1019 $block->add_child($positions);
1020
1021 // Transform configdata information if needed (process links and friends)
1022 $blockrec = $DB->get_record('block_instances', array('id' => $this->task->get_blockid()));
1023 if ($attrstotransform = $this->task->get_configdata_encoded_attributes()) {
1024 $configdata = (array)unserialize(base64_decode($blockrec->configdata));
1025 foreach ($configdata as $attribute => $value) {
1026 if (in_array($attribute, $attrstotransform)) {
1027 $configdata[$attribute] = $this->contenttransformer->process($value);
1028 }
1029 }
1030 $blockrec->configdata = base64_encode(serialize((object)$configdata));
1031 }
5f8354eb 1032 $blockrec->contextid = $this->task->get_contextid();
77547b46
EL
1033 // Get the version of the block
1034 $blockrec->version = $DB->get_field('block', 'version', array('name' => $this->task->get_blockname()));
1035
1036 // Define sources
1037
1038 $block->set_source_array(array($blockrec));
1039
1040 $positions->set_source_table('block_positions', array('blockinstanceid' => backup::VAR_PARENTID));
1041
1042 // Return the root element (block)
1043 return $block;
1044 }
1045}
1046
1047/**
1048 * structure step in charge of constructing the logs.xml file for all the log records found
1049 * in activity
1050 */
1051class backup_activity_logs_structure_step extends backup_structure_step {
1052
1053 protected function define_structure() {
1054
1055 // Define each element separated
1056
1057 $logs = new backup_nested_element('logs');
1058
1059 $log = new backup_nested_element('log', array('id'), array(
1060 'time', 'userid', 'ip', 'module',
1061 'action', 'url', 'info'));
1062
1063 // Build the tree
1064
1065 $logs->add_child($log);
1066
1067 // Define sources
1068
1069 $log->set_source_table('log', array('cmid' => backup::VAR_MODID));
1070
1071 // Annotations
1072 // NOTE: We don't annotate users from logs as far as they MUST be
1073 // always annotated by the activity.
1074
1075 // Return the root element (logs)
1076
1077 return $logs;
1078 }
1079}
1080
1081/**
1082 * structure in charge of constructing the inforef.xml file for all the items we want
1083 * to have referenced there (users, roles, files...)
1084 */
1085class backup_inforef_structure_step extends backup_structure_step {
1086
1087 protected function define_structure() {
1088
1089 // Items we want to include in the inforef file. NOTE: Important to keep this
1090 // list 100% sync with the one in next step! Until we get better place for it (backup:CONST)
1091 $items = array('user', 'grouping', 'group', 'role', 'file', 'scale', 'outcome', 'grade_item');
1092
1093 // Build the tree
1094
1095 $inforef = new backup_nested_element('inforef');
1096
1097 // For each item, conditionally, if there are already records, build element
1098 foreach ($items as $itemname) {
1099 if (backup_structure_dbops::annotations_exist($this->get_backupid(), $itemname)) {
1100 $elementroot = new backup_nested_element($itemname . 'ref');
1101 $element = new backup_nested_element($itemname, array('id'));
1102 $inforef->add_child($elementroot);
1103 $elementroot->add_child($element);
1104 $element->set_source_sql("
1105 SELECT itemid AS id
1106 FROM {backup_ids_temp}
1107 WHERE backupid = ?
1108 AND itemname = ?",
c0bd6249 1109 array(backup::VAR_BACKUPID, backup_helper::is_sqlparam($itemname)));
77547b46
EL
1110 }
1111 }
1112
1113 // We don't annotate anything there, but rely in the next step
1114 // (move_inforef_annotations_to_final) that will change all the
1115 // already saved 'inforref' entries to their 'final' annotations.
1116 return $inforef;
1117 }
1118}
1119
1120/**
1121 * This step will get all the annotations already processed to inforef.xml file and
1122 * transform them into 'final' annotations.
1123 */
1124class move_inforef_annotations_to_final extends backup_execution_step {
1125
1126 protected function define_execution() {
1127
1128 // Items we want to include in the inforef file. NOTE: Important to keep this
1129 // list 100% sync with the one in prev step! Until we get better place for it (backup:CONST)
1130 $items = array('user', 'grouping', 'group', 'role', 'file', 'scale', 'outcome', 'grade_item');
1131 foreach ($items as $itemname) {
1132 // Delegate to dbops
1133 backup_structure_dbops::move_annotations_to_final($this->get_backupid(), $itemname);
1134 }
1135 }
1136}
1137
1138/**
1139 * structure in charge of constructing the files.xml file with all the
1140 * annotated (final) files along the process. At, the same time, and
1141 * using one specialised nested_element, will copy them form moodle storage
1142 * to backup storage
1143 */
1144class backup_final_files_structure_step extends backup_structure_step {
1145
1146 protected function define_structure() {
1147
1148 // Define elements
1149
1150 $files = new backup_nested_element('files');
1151
1152 $file = new file_nested_element('file', array('id'), array(
64f93798 1153 'contenthash', 'contextid', 'component', 'filearea', 'itemid',
77547b46
EL
1154 'filepath', 'filename', 'userid', 'filesize',
1155 'mimetype', 'status', 'timecreated', 'timemodified',
1fd3ea43 1156 'source', 'author', 'license', 'sortorder'));
77547b46
EL
1157
1158 // Build the tree
1159
1160 $files->add_child($file);
1161
1162 // Define sources
1163
1164 $file->set_source_sql("SELECT f.*
1165 FROM {files} f
1166 JOIN {backup_ids_temp} bi ON f.id = bi.itemid
1167 WHERE bi.backupid = ?
1168 AND bi.itemname = 'filefinal'", array(backup::VAR_BACKUPID));
1169
1170 return $files;
1171 }
1172}
1173
1174/**
1175 * Structure step in charge of creating the main moodle_backup.xml file
1176 * where all the information related to the backup, settings, license and
1177 * other information needed on restore is added*/
1178class backup_main_structure_step extends backup_structure_step {
1179
1180 protected function define_structure() {
1181
1182 global $CFG;
1183
1184 $info = array();
1185
1186 $info['name'] = $this->get_setting_value('filename');
1187 $info['moodle_version'] = $CFG->version;
1188 $info['moodle_release'] = $CFG->release;
1189 $info['backup_version'] = $CFG->backup_version;
1190 $info['backup_release'] = $CFG->backup_release;
1191 $info['backup_date'] = time();
1192 $info['backup_uniqueid']= $this->get_backupid();
1193 $info['original_wwwroot']=$CFG->wwwroot;
1194 $info['original_site_identifier'] = get_site_identifier();
1195 $info['original_course_id'] = $this->get_courseid();
1196
1197 // Get more information from controller
1198 list($dinfo, $cinfo, $sinfo) = backup_controller_dbops::get_moodle_backup_information($this->get_backupid());
1199
1200 // Define elements
1201
1202 $moodle_backup = new backup_nested_element('moodle_backup');
1203
1204 $information = new backup_nested_element('information', null, array(
1205 'name', 'moodle_version', 'moodle_release', 'backup_version',
1206 'backup_release', 'backup_date', 'original_wwwroot',
1207 'original_site_identifier', 'original_course_id'));
1208
1209 $details = new backup_nested_element('details');
1210
1211 $detail = new backup_nested_element('detail', array('backup_id'), array(
1212 'type', 'format', 'interactive', 'mode',
1213 'execution', 'executiontime'));
1214
1215 $contents = new backup_nested_element('contents');
1216
1217 $activities = new backup_nested_element('activities');
1218
1219 $activity = new backup_nested_element('activity', null, array(
1220 'moduleid', 'sectionid', 'modulename', 'title',
1221 'directory'));
1222
1223 $sections = new backup_nested_element('sections');
1224
1225 $section = new backup_nested_element('section', null, array(
1226 'sectionid', 'title', 'directory'));
1227
1228 $course = new backup_nested_element('course', null, array(
1229 'courseid', 'title', 'directory'));
1230
1231 $settings = new backup_nested_element('settings');
1232
1233 $setting = new backup_nested_element('setting', null, array(
d12fd69b 1234 'level', 'section', 'activity', 'name', 'value'));
77547b46
EL
1235
1236 // Build the tree
1237
1238 $moodle_backup->add_child($information);
1239
1240 $information->add_child($details);
1241 $details->add_child($detail);
1242
1243 $information->add_child($contents);
1244 if (!empty($cinfo['activities'])) {
1245 $contents->add_child($activities);
1246 $activities->add_child($activity);
1247 }
1248 if (!empty($cinfo['sections'])) {
1249 $contents->add_child($sections);
1250 $sections->add_child($section);
1251 }
1252 if (!empty($cinfo['course'])) {
1253 $contents->add_child($course);
1254 }
1255
1256 $information->add_child($settings);
1257 $settings->add_child($setting);
1258
1259
1260 // Set the sources
1261
1262 $information->set_source_array(array((object)$info));
1263
1264 $detail->set_source_array($dinfo);
1265
1266 $activity->set_source_array($cinfo['activities']);
1267
1268 $section->set_source_array($cinfo['sections']);
1269
1270 $course->set_source_array($cinfo['course']);
1271
1272 $setting->set_source_array($sinfo);
1273
1274 // Prepare some information to be sent to main moodle_backup.xml file
1275 return $moodle_backup;
1276 }
1277
1278}
1279
ce937f99
EL
1280/**
1281 * Execution step that will generate the final zip file with all the contents
1282 */
1283class backup_zip_contents extends backup_execution_step {
1284
1285 protected function define_execution() {
1286
1287 // Get basepath
1288 $basepath = $this->get_basepath();
1289
1290 // Get the list of files in directory
1291 $filestemp = get_directory_list($basepath, '', false, true, true);
1292 $files = array();
1293 foreach ($filestemp as $file) { // Add zip paths and fs paths to all them
1294 $files[$file] = $basepath . '/' . $file;
1295 }
1296
1297 // Add the log file if exists
1298 $logfilepath = $basepath . '.log';
1299 if (file_exists($logfilepath)) {
1300 $files['moodle_backup.log'] = $logfilepath;
1301 }
1302
9eeaea5f
EL
1303 // Calculate the zip fullpath (in OS temp area it's always backup.zip)
1304 $zipfile = $basepath . '/backup.zip';
ce937f99
EL
1305
1306 // Get the zip packer
1307 $zippacker = get_file_packer('application/zip');
1308
1309 // Zip files
1310 $zippacker->archive_to_pathname($files, $zipfile);
1311 }
1312}
1313
1314/**
1315 * This step will send the generated backup file to its final destination
1316 */
1317class backup_store_backup_file extends backup_execution_step {
1318
1319 protected function define_execution() {
1320
1321 // Get basepath
1322 $basepath = $this->get_basepath();
1323
9eeaea5f
EL
1324 // Calculate the zip fullpath (in OS temp area it's always backup.zip)
1325 $zipfile = $basepath . '/backup.zip';
ce937f99
EL
1326
1327 // Perform storage and return it (TODO: shouldn't be array but proper result object)
1328 return array('backup_destination' => backup_helper::store_backup_file($this->get_backupid(), $zipfile));
1329 }
1330}
1331
1332
77547b46
EL
1333/**
1334 * This step will search for all the activity (not calculations, categories nor aggregations) grade items
1335 * and put them to the backup_ids tables, to be used later as base to backup them
1336 */
1337class backup_activity_grade_items_to_ids extends backup_execution_step {
1338
1339 protected function define_execution() {
1340
1341 // Fetch all activity grade items
1342 if ($items = grade_item::fetch_all(array(
1343 'itemtype' => 'mod', 'itemmodule' => $this->task->get_modulename(),
1344 'iteminstance' => $this->task->get_activityid(), 'courseid' => $this->task->get_courseid()))) {
1345 // Annotate them in backup_ids
1346 foreach ($items as $item) {
1347 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'grade_item', $item->id);
1348 }
1349 }
1350 }
1351}
1352
1353/**
1354 * This step will annotate all the groups belonging to already annotated groupings
1355 */
1356class backup_annotate_groups_from_groupings extends backup_execution_step {
1357
1358 protected function define_execution() {
1359 global $DB;
1360
1361 // Fetch all the annotated groupings
1362 if ($groupings = $DB->get_records('backup_ids_temp', array(
1363 'backupid' => $this->get_backupid(), 'itemname' => 'grouping'))) {
1364 foreach ($groupings as $grouping) {
1365 if ($groups = $DB->get_records('groupings_groups', array(
1366 'groupingid' => $grouping->itemid))) {
1367 foreach ($groups as $group) {
1368 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'group', $group->groupid);
1369 }
1370 }
1371 }
1372 }
1373 }
1374}
1375
1376/**
1377 * This step will annotate all the scales belonging to already annotated outcomes
1378 */
1379class backup_annotate_scales_from_outcomes extends backup_execution_step {
1380
1381 protected function define_execution() {
1382 global $DB;
1383
1384 // Fetch all the annotated outcomes
1385 if ($outcomes = $DB->get_records('backup_ids_temp', array(
1386 'backupid' => $this->get_backupid(), 'itemname' => 'outcome'))) {
1387 foreach ($outcomes as $outcome) {
1388 if ($scale = $DB->get_record('grade_outcomes', array(
1389 'id' => $outcome->itemid))) {
1390 // Annotate as scalefinal because it's > 0
1391 backup_structure_dbops::insert_backup_ids_record($this->get_backupid(), 'scalefinal', $scale->scaleid);
1392 }
1393 }
1394 }
1395 }
1396}
1397
1398/**
1399 * This step will generate all the user annotations for the already
39b5371c 1400 * annotated (final) users. Need to do this here because each user
77547b46
EL
1401 * has its own context and structure tasks only are able to handle
1402 * one context. Also, this step will guarantee that every user has
1403 * its context created (req for other steps)
1404 */
1405class backup_annotate_all_user_files extends backup_execution_step {
1406
1407 protected function define_execution() {
1408 global $DB;
1409
1410 // List of fileareas we are going to annotate
78d47b30 1411 $fileareas = array('private', 'profile', 'icon');
77547b46
EL
1412
1413 // Fetch all annotated (final) users
1414 $rs = $DB->get_recordset('backup_ids_temp', array(
1415 'backupid' => $this->get_backupid(), 'itemname' => 'userfinal'));
1416 foreach ($rs as $record) {
1417 $userid = $record->itemid;
1418 $userctxid = get_context_instance(CONTEXT_USER, $userid)->id;
1419 // Proceed with every user filearea
1420 foreach ($fileareas as $filearea) {
78d47b30 1421 // We don't need to specify itemid ($userid - 5th param) as far as by
77547b46 1422 // context we can get all the associated files. See MDL-22092
64f93798 1423 backup_structure_dbops::annotate_files($this->get_backupid(), $userctxid, 'user', $filearea, null);
77547b46
EL
1424 }
1425 }
1426 $rs->close();
1427 }
1428}
1429
1430/**
1431 * structure step in charge of constructing the grades.xml file for all the grade items
1432 * and letters related to one activity
1433 */
1434class backup_activity_grades_structure_step extends backup_structure_step {
1435
1436 protected function define_structure() {
1437
1438 // To know if we are including userinfo
1439 $userinfo = $this->get_setting_value('userinfo');
1440
1441 // Define each element separated
1442
1443 $book = new backup_nested_element('activity_gradebook');
1444
1445 $items = new backup_nested_element('grade_items');
1446
1447 $item = new backup_nested_element('grade_item', array('id'), array(
1448 'categoryid', 'itemname', 'itemtype', 'itemmodule',
1449 'iteminstance', 'itemnumber', 'iteminfo', 'idnumber',
1450 'calculation', 'gradetype', 'grademax', 'grademin',
1451 'scaleid', 'outcomeid', 'gradepass', 'multfactor',
1452 'plusfactor', 'aggregationcoef', 'sortorder', 'display',
1453 'decimals', 'hidden', 'locked', 'locktime',
1454 'needsupdate', 'timecreated', 'timemodified'));
1455
1456 $grades = new backup_nested_element('grade_grades');
1457
1458 $grade = new backup_nested_element('grade_grade', array('id'), array(
1459 'userid', 'rawgrade', 'rawgrademax', 'rawgrademin',
1460 'rawscaleid', 'usermodified', 'finalgrade', 'hidden',
1461 'locked', 'locktime', 'exported', 'overridden',
1462 'excluded', 'feedback', 'feedbackformat', 'information',
1463 'informationformat', 'timecreated', 'timemodified'));
1464
1465 $letters = new backup_nested_element('grade_letters');
1466
1467 $letter = new backup_nested_element('grade_letter', 'id', array(
1468 'lowerboundary', 'letter'));
1469
1470 // Build the tree
1471
1472 $book->add_child($items);
1473 $items->add_child($item);
1474
1475 $item->add_child($grades);
1476 $grades->add_child($grade);
1477
1478 $book->add_child($letters);
1479 $letters->add_child($letter);
1480
1481 // Define sources
1482
315f6d8e
AD
1483 $item->set_source_sql("SELECT gi.*
1484 FROM {grade_items} gi
1485 JOIN {backup_ids_temp} bi ON gi.id = bi.itemid
1486 WHERE bi.backupid = ?
1487 AND bi.itemname = 'grade_item'", array(backup::VAR_BACKUPID));
77547b46
EL
1488
1489 // This only happens if we are including user info
1490 if ($userinfo) {
1491 $grade->set_source_table('grade_grades', array('itemid' => backup::VAR_PARENTID));
1492 }
1493
1494 $letter->set_source_table('grade_letters', array('contextid' => backup::VAR_CONTEXTID));
1495
1496 // Annotations
1497
1498 $item->annotate_ids('scalefinal', 'scaleid'); // Straight as scalefinal because it's > 0
1499 $item->annotate_ids('outcome', 'outcomeid');
1500
1501 $grade->annotate_ids('user', 'userid');
1502 $grade->annotate_ids('user', 'usermodified');
1503
1504 // Return the root element (book)
1505
1506 return $book;
1507 }
1508}