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