Updated the HEAD build version to 20080816
[moodle.git] / lib / db / upgradelib.php
CommitLineData
42ff9ce6 1<?php //$Id$
2
3/*
4 * This file is used for special upgrade functions - for example groups and gradebook.
56a1a882 5 * These functions must use SQL and database related functions only- no other Moodle API,
42ff9ce6 6 * because it might depend on db structures that are not yet present during upgrade.
7 * (Do not use functions from accesslib.php, grades classes or group functions at all!)
8 */
9
863850d2 10function upgrade_fix_category_depths() {
f33e1ed4 11 global $CFG, $DB;
863850d2 12
13 // first fix incorrect parents
14 $sql = "SELECT c.id
f33e1ed4 15 FROM {course_categories} c
16 WHERE c.parent > 0 AND c.parent NOT IN (SELECT pc.id FROM {course_categories} pc)";
17 if ($rs = $DB->get_recordset_sql($sql)) {
18 foreach ($rs as $cat) {
863850d2 19 $cat->depth = 1;
20 $cat->path = '/'.$cat->id;
21 $cat->parent = 0;
f33e1ed4 22 $DB->update_record('course_categories', $cat);
863850d2 23 }
f33e1ed4 24 $rs->close();
863850d2 25 }
26
27 // now add path and depth to top level categories
f33e1ed4 28 $sql = "UPDATE {course_categories}
245ac557 29 SET depth = 1, path = ".$DB->sql_concat("'/'", "id")."
863850d2 30 WHERE parent = 0";
f33e1ed4 31 $DB->execute($sql);
863850d2 32
33 // now fix all other levels - slow but works in all supported dbs
34 $parentdepth = 1;
f33e1ed4 35 while ($DB->record_exists('course_categories', array('depth'=>0))) {
863850d2 36 $sql = "SELECT c.id, pc.path
f33e1ed4 37 FROM {course_categories} c, {course_categories} pc
38 WHERE c.parent=pc.id AND c.depth=0 AND pc.depth=?";
39 if ($rs = $DB->get_recordset_sql($sql, array($parentdepth))) {
40 $DB->set_debug(false);
41 foreach ($rs as $cat) {
863850d2 42 $cat->depth = $parentdepth+1;
43 $cat->path = $cat->path.'/'.$cat->id;
f33e1ed4 44 $DB->update_record('course_categories', $cat);
863850d2 45 }
f33e1ed4 46 $rs->close();
47 $DB->set_debug(false);
863850d2 48 }
49 $parentdepth++;
50 if ($parentdepth > 100) {
51 //something must have gone wrong - nobody can have more than 100 levels of categories, right?
52 debugging('Unknown error fixing category depths');
53 break;
54 }
55 }
863850d2 56}
57
172dd12c 58/**
59 * Moves all course files except the moddata to new file storage
60 *
61 * Unfortunately this function uses core file related functions - it might be necessary to tweak it if something changes there :-(
62 */
63function upgrade_migrate_files_courses() {
64 global $DB, $CFG;
65 require_once($CFG->libdir.'/filelib.php');
66
67 $count = $DB->count_records('course');
68 $pbar = new progress_bar('migratecoursefiles', 500, true);
69
70 $rs = $DB->get_recordset('course');
71 $olddebug = $DB->get_debug();
72 $DB->set_debug(false); // lower debug level, there might be many files
73 $i = 0;
74 foreach ($rs as $course) {
75 $i++;
76 $context = get_context_instance(CONTEXT_COURSE, $course->id);
77 upgrade_migrate_files_course($context, '/', true);
78 $pbar->update($i, $count, "Migrated course files - course $i/$count.");
79 }
80 $DB->set_debug($olddebug); // reset debug level
81 $rs->close();
82
83 return true;
84}
85
86/**
87 * Internal function - do not use directly
88 */
89function upgrade_migrate_files_course($context, $path, $delete) {
90 global $CFG;
91
92 $fullpathname = $CFG->dataroot.'/'.$context->instanceid.$path;
93 if (!file_exists($fullpathname)) {
94 return;
95 }
96 $items = new DirectoryIterator($fullpathname);
97 $fs = get_file_storage();
98
99 foreach ($items as $item) {
100 if ($item->isDot()) {
101 continue;
102 }
103
104 if ($item->isLink()) {
105 // do not delete symbolic links or its children
106 $delete_this = false;
107 } else {
108 $delete_this = $delete;
109 }
110
111 if (strpos($path, '/backupdata/') === 0) {
112 $filearea = 'course_backup';
113 $filepath = substr($path, strlen('/backupdata'));
114 } else {
115 $filearea = 'course_content';
116 $filepath = $path;
117 }
118
119 if ($item->isFile()) {
120 if (!$item->isReadable()) {
121 notify(" File not readable, skipping: ".$fullpathname.$item->getFilename());
122 continue;
123 }
124
125 $filepath = clean_param($filepath, PARAM_PATH);
126 $filename = clean_param($item->getFilename(), PARAM_FILE);
127
128 if ($filename === '') {
129 continue;
130 }
131
132 if (!$fs->file_exists($context->id, $filearea, '0', $filepath, $filename)) {
133 $file_record = array('contextid'=>$context->id, 'filearea'=>$filearea, 'itemid'=>0, 'filepath'=>$filepath, 'filename'=>$filename,
134 'timecreated'=>$item->getCTime(), 'timemodified'=>$item->getMTime());
135 if ($fs->create_file_from_pathname($file_record, $fullpathname.$item->getFilename())) {
136 if ($delete_this) {
137 @unlink($fullpathname.$item->getFilename());
138 }
139 }
140 }
141
142 } else {
143 if ($path == '/' and $item->getFilename() == 'moddata') {
144 continue; // modules are responsible
145 }
146
147 $filepath = clean_param($filepath.$item->getFilename().'/', PARAM_PATH);
148 if ($filepath !== '/backupdata/') {
149 $fs->create_directory($context->id, $filearea, 0, $filepath);
150 }
151
152 //migrate recursively all subdirectories
153 upgrade_migrate_files_course($context, $path.$item->getFilename().'/', $delete_this);
154 if ($delete_this) {
155 // delete dir if empty
156 @rmdir($fullpathname.$item->getFilename());
157 }
158 }
159 }
160 unset($items); //release file handles
161}
162
163/**
164 * Moves all block attachments
165 *
166 * Unfortunately this function uses core file related functions - it might be necessary to tweak it if something changes there :-(
167 */
168function upgrade_migrate_files_blog() {
169 global $DB, $CFG;
170
171 $fs = get_file_storage();
172
173 $count = $DB->count_records_select('post', "module='blog' AND attachment IS NOT NULL AND attachment <> 1");
174
175 if ($rs = $DB->get_recordset_select('post', "module='blog' AND attachment IS NOT NULL AND attachment <> 1")) {
176
177 $pbar = new progress_bar('migrateblogfiles', 500, true);
178
179 $olddebug = $DB->get_debug();
180 $DB->set_debug(false); // lower debug level, there might be many files
181 $i = 0;
182 foreach ($rs as $entry) {
183 $i++;
184 $pathname = "$CFG->dataroot/blog/attachments/$entry->id/$entry->attachment";
185 if (!file_exists($pathname)) {
186 // hmm, we could set atatchment NULL here, but it would break badly in concurrent ugprades, disabling for now
187 //$entry->attachment = NULL;
188 //$DB->update_record('post', $entry);
189 continue;
190 }
191
192 $filename = clean_param($entry->attachment, PARAM_FILE);
193 if ($filename === '') {
194 // weird file name, ignore it
195 $entry->attachment = NULL;
196 $DB->update_record('post', $entry);
197 continue;
198 }
199
200 if (!is_readable($pathname)) {
201 notify(" File not readable, skipping: ".$pathname);
202 continue;
203 }
204
205 if (!$fs->file_exists(SYSCONTEXTID, 'blog', $entry->id, '/', $filename)) {
206 $file_record = array('contextid'=>SYSCONTEXTID, 'filearea'=>'blog', 'itemid'=>$entry->id, 'filepath'=>'/', 'filename'=>$filename,
207 'timecreated'=>filectime($pathname), 'timemodified'=>filemtime($pathname), 'userid'=>$post->userid);
208 $fs->create_file_from_pathname($file_record, $pathname);
209 }
210 @unlink($pathname);
211 @rmdir("$CFG->dataroot/blog/attachments/$entry->id/");
212
213 $entry->attachment = 1; // file name not needed there anymore
214 $DB->update_record('post', $entry);
215 $pbar->update($i, $count, "Migrated blog attachments - $i/$count.");
216 }
217 $DB->set_debug($olddebug); // reset debug level
218 $rs->close();
219 }
220
221 @rmdir("$CFG->dataroot/blog/attachments/");
222 @rmdir("$CFG->dataroot/blog/");
223}