MDL-35297 book: replay some steps lost when book landed to core
[moodle.git] / mod / book / db / upgradelib.php
1 <?php
2 // This file is part of Book module for Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Book module upgrade related helper functions
19  *
20  * @package    mod_book
21  * @copyright  2010 Petr Skoda {@link http://skodak.org}
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die;
27 /**
28  * Migrate book files stored in moddata folders.
29  *
30  * Please note it was a big mistake to store the files there in the first place!
31  *
32  * @param stdClass $book
33  * @param stdClass $context
34  * @param string $path
35  * @return void
36  */
37 function mod_book_migrate_moddata_dir_to_legacy($book, $context, $path) {
38     global $OUTPUT, $CFG;
40     $base = "$CFG->dataroot/$book->course/$CFG->moddata/book/$book->id";
41     $fulldir = $base.$path;
43     if (!is_dir($fulldir)) {
44         // does not exist
45         return;
46     }
48     $fs      = get_file_storage();
49     $items   = new DirectoryIterator($fulldir);
51     foreach ($items as $item) {
52         if ($item->isDot()) {
53             unset($item); // release file handle
54             continue;
55         }
57         if ($item->isLink()) {
58             // do not follow symlinks - they were never supported in moddata, sorry
59             unset($item); // release file handle
60             continue;
61         }
63         if ($item->isFile()) {
64             if (!$item->isReadable()) {
65                 echo $OUTPUT->notification(" File not readable, skipping: ".$fulldir.$item->getFilename());
66                 unset($item); // release file handle
67                 continue;
68             }
70             $filepath = clean_param("/$CFG->moddata/book/$book->id".$path, PARAM_PATH);
71             $filename = clean_param($item->getFilename(), PARAM_FILE);
73             if ($filename === '') {
74                 // unsupported chars, sorry
75                 unset($item); // release file handle
76                 continue;
77             }
79             if (textlib::strlen($filepath) > 255) {
80                 echo $OUTPUT->notification(" File path longer than 255 chars, skipping: ".$fulldir.$item->getFilename());
81                 unset($item); // release file handle
82                 continue;
83             }
85             if (!$fs->file_exists($context->id, 'course', 'legacy', '0', $filepath, $filename)) {
86                 $file_record = array('contextid'=>$context->id, 'component'=>'course', 'filearea'=>'legacy', 'itemid'=>0, 'filepath'=>$filepath, 'filename'=>$filename,
87                                      'timecreated'=>$item->getCTime(), 'timemodified'=>$item->getMTime());
88                 $fs->create_file_from_pathname($file_record, $fulldir.$item->getFilename());
89             }
90             $oldpathname = $fulldir.$item->getFilename();
91             unset($item); // release file handle
92             @unlink($oldpathname);
94         } else {
95             // migrate recursively all subdirectories
96             $oldpathname = $base.$item->getFilename().'/';
97             $subpath     = $path.$item->getFilename().'/';
98             unset($item);  // release file handle
99             mod_book_migrate_moddata_dir_to_legacy($book, $context, $subpath);
100             @rmdir($oldpathname); // deletes dir if empty
101         }
102     }
103     unset($items); // release file handles
106 /**
107  * Migrate legacy files in intro and chapters
108  * @return void
109  */
110 function mod_book_migrate_all_areas() {
111     global $DB;
113     $rsbooks = $DB->get_recordset('book');
114     foreach($rsbooks as $book) {
115         upgrade_set_timeout(360); // set up timeout, may also abort execution
116         $cm = get_coursemodule_from_instance('book', $book->id);
117         $context = context_module::instance($cm->id);
118         mod_book_migrate_area($book, 'intro', 'book', $book->course, $context, 'mod_book', 'intro', 0);
120         $rschapters = $DB->get_recordset('book_chapters', array('bookid'=>$book->id));
121         foreach ($rschapters as $chapter) {
122             mod_book_migrate_area($chapter, 'content', 'book_chapters', $book->course, $context, 'mod_book', 'chapter', $chapter->id);
123         }
124         $rschapters->close();
125     }
126     $rsbooks->close();
129 /**
130  * Migrate one area, this should be probably part of moodle core...
131  *
132  * @param stdClass $record object to migrate files (book, chapter)
133  * @param string $field field in the record we are going to migrate
134  * @param string $table DB table containing the information to migrate
135  * @param int $courseid id of the course the book module belongs to
136  * @param context_module $context context of the book module
137  * @param string $component component to be used for the migrated files
138  * @param string $filearea filearea to be used for the migrated files
139  * @param int $itemid id to be used for the migrated files
140  * @return void
141  */
142 function mod_book_migrate_area($record, $field, $table, $courseid, $context, $component, $filearea, $itemid) {
143     global $CFG, $DB;
145     $fs = get_file_storage();
147     foreach(array(get_site()->id, $courseid) as $cid) {
148         $matches = null;
149         $ooldcontext = context_course::instance($cid);
150         if (preg_match_all("|$CFG->wwwroot/file.php(\?file=)?/$cid(/[^\s'\"&\?#]+)|", $record->$field, $matches)) {
151             $file_record = array('contextid'=>$context->id, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid);
152             foreach ($matches[2] as $i=>$filepath) {
153                 if (!$file = $fs->get_file_by_hash(sha1("/$ooldcontext->id/course/legacy/0".$filepath))) {
154                     continue;
155                 }
156                 try {
157                     if (!$newfile = $fs->get_file_by_hash(sha1("/$context->id/$component/$filearea/$itemid".$filepath))) {
158                         $fs->create_file_from_storedfile($file_record, $file);
159                     }
160                     $record->$field = str_replace($matches[0][$i], '@@PLUGINFILE@@'.$filepath, $record->$field);
161                 } catch (Exception $ex) {
162                     // ignore problems
163                 }
164                 $DB->set_field($table, $field, $record->$field, array('id'=>$record->id));
165             }
166         }
167     }