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