MDL-23109 backup - exclude info in moodle_backup.xml about non-included task. Thanks...
[moodle.git] / backup / util / dbops / backup_controller_dbops.class.php
CommitLineData
69dd0c8c
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-dbops
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 * Non instantiable helper class providing DB support to the @backup_controller
27 *
28 * This class contains various static methods available for all the DB operations
29 * performed by the backup_controller class
30 *
31 * TODO: Finish phpdocs
32 */
33abstract class backup_controller_dbops extends backup_dbops {
34
35 public static function save_controller($controller, $checksum) {
36 global $DB;
37 // Check we are going to save one backup_controller
38 if (! $controller instanceof backup_controller) {
39 throw new backup_controller_exception('backup_controller_expected');
40 }
41 // Check checksum is ok. Sounds silly but it isn't ;-)
42 if (!$controller->is_checksum_correct($checksum)) {
43 throw new backup_dbops_exception('backup_controller_dbops_saving_checksum_mismatch');
44 }
45 // Get all the columns
46 $rec = new stdclass();
47 $rec->backupid = $controller->get_backupid();
f60f4666 48 $rec->operation = $controller->get_operation();
69dd0c8c
EL
49 $rec->type = $controller->get_type();
50 $rec->itemid = $controller->get_id();
51 $rec->format = $controller->get_format();
52 $rec->interactive = $controller->get_interactive();
53 $rec->purpose = $controller->get_mode();
54 $rec->userid = $controller->get_userid();
55 $rec->status = $controller->get_status();
56 $rec->execution = $controller->get_execution();
57 $rec->executiontime= $controller->get_executiontime();
58 $rec->checksum = $checksum;
59 // Serialize information
60 $rec->controller = base64_encode(serialize($controller));
61 // Send it to DB
62 if ($recexists = $DB->get_record('backup_controllers', array('backupid' => $rec->backupid))) {
63 $rec->id = $recexists->id;
64 $rec->timemodified = time();
65 $DB->update_record('backup_controllers', $rec);
66 } else {
67 $rec->timecreated = time();
68 $rec->timemodified = 0;
69 $rec->id = $DB->insert_record('backup_controllers', $rec);
70 }
71 return $rec->id;
72 }
73
74 public static function load_controller($backupid) {
75 global $DB;
76 if (! $controllerrec = $DB->get_record('backup_controllers', array('backupid' => $backupid))) {
77 throw new backup_dbops_exception('backup_controller_dbops_nonexisting');
78 }
79 $controller = unserialize(base64_decode($controllerrec->controller));
80 // Check checksum is ok. Sounds silly but it isn't ;-)
81 if (!$controller->is_checksum_correct($controllerrec->checksum)) {
82 throw new backup_dbops_exception('backup_controller_dbops_loading_checksum_mismatch');
83 }
84 return $controller;
85 }
86
87 public static function create_backup_ids_temp_table($backupid) {
b8bb45b0
EL
88 self::create_temptable_from_real_table($backupid, 'backup_ids_template', 'backup_ids_temp');
89 }
90
91 /**
92 * Given one "real" tablename, create one temp table suitable for be used in backup/restore operations
93 */
94 public static function create_temptable_from_real_table($backupid, $realtablename, $temptablename) {
69dd0c8c
EL
95 global $CFG, $DB;
96 $dbman = $DB->get_manager(); // We are going to use database_manager services
97
b8bb45b0 98 // Note: For now we are going to load the realtablename from core lib/db/install.xml
69dd0c8c
EL
99 // that way, any change in the "template" will be applied here automatically. If this causes
100 // too much slow, we can always forget about the template and keep maintained the xmldb_table
101 // structure inline - manually - here.
b8bb45b0
EL
102 $templatetablename = $realtablename;
103 $targettablename = $temptablename;
104 $xmlfile = $CFG->dirroot . '/lib/db/install.xml';
105 $xmldb_file = new xmldb_file($xmlfile);
69dd0c8c
EL
106 if (!$xmldb_file->fileExists()) {
107 throw new ddl_exception('ddlxmlfileerror', null, 'File does not exist');
108 }
109 $loaded = $xmldb_file->loadXMLStructure();
110 if (!$loaded || !$xmldb_file->isLoaded()) {
111 throw new ddl_exception('ddlxmlfileerror', null, 'not loaded??');
112 }
113 $xmldb_structure = $xmldb_file->getStructure();
114 $xmldb_table = $xmldb_structure->getTable($templatetablename);
115 if (is_null($xmldb_table)) {
b8bb45b0 116 throw new ddl_exception('ddlunknowntable', null, 'The table ' . $templatetablename . ' is not defined in file ' . $xmlfile);
69dd0c8c
EL
117 }
118 // Set default backupid (not needed but this enforce any missing backupid). That's hackery in action!
119 $xmldb_table->getField('backupid')->setDefault($backupid);
120 // Clean prev & next, we are alone
121 $xmldb_table->setNext(null);
122 $xmldb_table->setPrevious(null);
123 // Rename
124 $xmldb_table->setName($targettablename);
125
126 $dbman->create_temp_table($xmldb_table); // And create it
127 }
128
129 public static function drop_backup_ids_temp_table($backupid) {
130 global $DB;
131 $dbman = $DB->get_manager(); // We are going to use database_manager services
132
133 $targettablename = 'backup_ids_temp';
134 $table = new xmldb_table($targettablename);
135 $dbman->drop_temp_table($table); // And drop it
136 }
137
138 /**
139 * Given one type and id from controller, return the corresponding courseid
140 */
141 public static function get_courseid_from_type_id($type, $id) {
142 global $DB;
143 if ($type == backup::TYPE_1COURSE) {
144 return $id; // id is the course id
145
146 } else if ($type == backup::TYPE_1SECTION) {
147 if (! $courseid = $DB->get_field('course_sections', 'course', array('id' => $id))) {
148 throw new backup_dbops_exception('course_not_found_for_section', $id);
149 }
150 return $courseid;
151 } else if ($type == backup::TYPE_1ACTIVITY) {
152 if (! $courseid = $DB->get_field('course_modules', 'course', array('id' => $id))) {
153 throw new backup_dbops_exception('course_not_found_for_moduleid', $id);
154 }
155 return $courseid;
156 }
157 }
158
159 /**
160 * Given one activity task, return the activity information and related settings
161 * Used by get_moodle_backup_information()
162 */
163 private static function get_activity_backup_information($task) {
164
165 $contentinfo = array(
166 'moduleid' => $task->get_moduleid(),
167 'sectionid' => $task->get_sectionid(),
168 'modulename' => $task->get_modulename(),
169 'title' => $task->get_name(),
170 'directory' => 'activities/' . $task->get_modulename() . '_' . $task->get_moduleid());
171
172 // Now get activity settings
173 // Calculate prefix to find valid settings
174 $prefix = basename($contentinfo['directory']);
175 $settingsinfo = array();
176 foreach ($task->get_settings() as $setting) {
177 // Discard ones without valid prefix
178 if (strpos($setting->get_name(), $prefix) !== 0) {
179 continue;
180 }
181 // Validate level is correct (activity)
182 if ($setting->get_level() != backup_setting::ACTIVITY_LEVEL) {
183 throw new backup_controller_exception('setting_not_activity_level', $setting);
184 }
185 $settinginfo = array(
186 'level' => 'activity',
187 'activity' => $prefix,
188 'name' => $setting->get_name(),
189 'value' => $setting->get_value());
ce937f99 190 $settingsinfo[$setting->get_name()] = (object)$settinginfo;
69dd0c8c
EL
191 }
192 return array($contentinfo, $settingsinfo);
193 }
194
195 /**
196 * Given one section task, return the section information and related settings
197 * Used by get_moodle_backup_information()
198 */
199 private static function get_section_backup_information($task) {
200
201 $contentinfo = array(
202 'sectionid' => $task->get_sectionid(),
203 'title' => $task->get_name(),
204 'directory' => 'sections/' . 'section_' . $task->get_sectionid());
205
206 // Now get section settings
207 // Calculate prefix to find valid settings
208 $prefix = basename($contentinfo['directory']);
209 $settingsinfo = array();
210 foreach ($task->get_settings() as $setting) {
211 // Discard ones without valid prefix
212 if (strpos($setting->get_name(), $prefix) !== 0) {
213 continue;
214 }
215 // Validate level is correct (section)
216 if ($setting->get_level() != backup_setting::SECTION_LEVEL) {
217 throw new backup_controller_exception('setting_not_section_level', $setting);
218 }
219 $settinginfo = array(
220 'level' => 'section',
d12fd69b 221 'section' => $prefix,
69dd0c8c
EL
222 'name' => $setting->get_name(),
223 'value' => $setting->get_value());
ce937f99 224 $settingsinfo[$setting->get_name()] = (object)$settinginfo;
69dd0c8c
EL
225 }
226 return array($contentinfo, $settingsinfo);
227 }
228
229 /**
230 * Given one course task, return the course information and related settings
231 * Used by get_moodle_backup_information()
232 */
233 private static function get_course_backup_information($task) {
234
235 $contentinfo = array(
236 'courseid' => $task->get_courseid(),
237 'title' => $task->get_name(),
238 'directory' => 'course');
239
240 // Now get course settings
241 // Calculate prefix to find valid settings
242 $prefix = basename($contentinfo['directory']);
243 $settingsinfo = array();
244 foreach ($task->get_settings() as $setting) {
245 // Discard ones without valid prefix
246 if (strpos($setting->get_name(), $prefix) !== 0) {
247 continue;
248 }
249 // Validate level is correct (course)
250 if ($setting->get_level() != backup_setting::COURSE_LEVEL) {
251 throw new backup_controller_exception('setting_not_course_level', $setting);
252 }
253 $settinginfo = array(
254 'level' => 'course',
255 'name' => $setting->get_name(),
256 'value' => $setting->get_value());
ce937f99 257 $settingsinfo[$setting->get_name()] = (object)$settinginfo;
69dd0c8c
EL
258 }
259 return array($contentinfo, $settingsinfo);
260 }
261
262 /**
263 * Given one root task, return the course information and related settings
264 * Used by get_moodle_backup_information()
265 */
266 private static function get_root_backup_information($task) {
267
268 // Now get root settings
269 $settingsinfo = array();
270 foreach ($task->get_settings() as $setting) {
271 // Validate level is correct (root)
272 if ($setting->get_level() != backup_setting::ROOT_LEVEL) {
273 throw new backup_controller_exception('setting_not_root_level', $setting);
274 }
275 $settinginfo = array(
276 'level' => 'root',
277 'name' => $setting->get_name(),
278 'value' => $setting->get_value());
ce937f99 279 $settingsinfo[$setting->get_name()] = (object)$settinginfo;
69dd0c8c
EL
280 }
281 return array(null, $settingsinfo);
282 }
283
284 /**
285 * Get details information for main moodle_backup.xml file, extracting it from
286 * the specified controller
287 */
288 public static function get_moodle_backup_information($backupid) {
289
290 $detailsinfo = array(); // Information details
291 $contentsinfo= array(); // Information about backup contents
292 $settingsinfo= array(); // Information about backup settings
293 $bc = self::load_controller($backupid); // Load controller
294
295 // Details info
cd0034d8 296 $detailsinfo['id'] = $bc->get_id();
69dd0c8c
EL
297 $detailsinfo['backup_id'] = $bc->get_backupid();
298 $detailsinfo['type'] = $bc->get_type();
299 $detailsinfo['format'] = $bc->get_format();
300 $detailsinfo['interactive'] = $bc->get_interactive();
301 $detailsinfo['mode'] = $bc->get_mode();
302 $detailsinfo['execution'] = $bc->get_execution();
303 $detailsinfo['executiontime'] = $bc->get_executiontime();
ce937f99 304 $detailsinfo['userid'] = $bc->get_userid();
cd0034d8 305 $detailsinfo['courseid'] = $bc->get_courseid();
69dd0c8c
EL
306
307
308 // Init content placeholders
309 $contentsinfo['activities'] = array();
310 $contentsinfo['sections'] = array();
311 $contentsinfo['course'] = array();
312
313 // Contents info (extract information from tasks)
314 foreach ($bc->get_plan()->get_tasks() as $task) {
315
316 if ($task instanceof backup_activity_task) { // Activity task
317
fbd74137
EL
318 if ($task->get_setting_value('included')) { // Only return info about included activities
319 list($contentinfo, $settings) = self::get_activity_backup_information($task);
320 $contentsinfo['activities'][] = $contentinfo;
321 $settingsinfo = array_merge($settingsinfo, $settings);
322 }
69dd0c8c
EL
323
324 } else if ($task instanceof backup_section_task) { // Section task
325
fbd74137
EL
326 if ($task->get_setting_value('included')) { // Only return info about included sections
327 list($contentinfo, $settings) = self::get_section_backup_information($task);
328 $contentsinfo['sections'][] = $contentinfo;
329 $settingsinfo = array_merge($settingsinfo, $settings);
330 }
69dd0c8c
EL
331
332 } else if ($task instanceof backup_course_task) { // Course task
333
334 list($contentinfo, $settings) = self::get_course_backup_information($task);
335 $contentsinfo['course'][] = $contentinfo;
336 $settingsinfo = array_merge($settingsinfo, $settings);
337
338 } else if ($task instanceof backup_root_task) { // Root task
339
340 list($contentinfo, $settings) = self::get_root_backup_information($task);
341 $settingsinfo = array_merge($settingsinfo, $settings);
342 }
343 }
344
345 return array(array((object)$detailsinfo), $contentsinfo, $settingsinfo);
346 }
347
348 /**
349 * Update CFG->backup_version and CFG->backup_release if change in
350 * version is detected.
351 */
352 public static function apply_version_and_release() {
353 global $CFG;
354
355 if ($CFG->backup_version < backup::VERSION) {
356 set_config('backup_version', backup::VERSION);
357 set_config('backup_release', backup::RELEASE);
358 }
359 }
61ebef8f 360
c3ea499d
EL
361 /**
362 * Given the backupid, detect if the backup includes "mnet" remote users or no
363 */
364 public static function backup_includes_mnet_remote_users($backupid) {
365 global $CFG, $DB;
366
367 $sql = "SELECT COUNT(*)
368 FROM {backup_ids_temp} b
369 JOIN {user} u ON u.id = b.itemid
370 WHERE b.backupid = ?
371 AND b.itemname = 'userfinal'
372 AND u.mnethostid != ?";
373 $count = $DB->count_records_sql($sql, array($backupid, $CFG->mnet_localhost_id));
374 return (int)(bool)$count;
375 }
376
560811a9
EL
377 /**
378 * Given the courseid, return some course related information we want to transport
379 *
380 * @param int $course the id of the course this backup belongs to
381 */
382 public static function backup_get_original_course_info($courseid) {
383 global $DB;
384 return $DB->get_record('course', array('id' => $courseid), 'fullname, shortname, startdate');
385 }
386
61ebef8f
SH
387 /**
388 * Sets the controller settings default values from the backup config.
560811a9 389 *
61ebef8f
SH
390 * @param backup_controller $controller
391 */
392 public static function apply_general_config_defaults(backup_controller $controller) {
393 $settings = array(
394 // Config name => Setting name
395 'backup_general_users' => 'users',
396 'backup_general_anonymize' => 'anonymize',
397 'backup_general_role_assignments' => 'role_assignments',
398 'backup_general_user_files' => 'user_files',
399 'backup_general_activities' => 'activities',
400 'backup_general_blocks' => 'blocks',
401 'backup_general_filters' => 'filters',
402 'backup_general_comments' => 'comments',
403 'backup_general_userscompletion' => 'userscompletion',
404 'backup_general_logs' => 'logs',
405 'backup_general_histories' => 'grade_histories'
406 );
407 $plan = $controller->get_plan();
408 foreach ($settings as $config=>$settingname) {
409 $value = get_config('backup', $config);
410 $locked = (get_config('backup', $config.'_locked') == true);
411 if ($plan->setting_exists($settingname)) {
412 $setting = $plan->get_setting($settingname);
413 if ($setting->get_value() != $value || 1==1) {
414 $setting->set_value($value);
415 if ($locked) {
416 $setting->set_status(base_setting::LOCKED_BY_CONFIG);
417 }
418 }
419 }
420 }
421 }
69dd0c8c 422}