Backup - mod lesson conversion: apply jumpto fix only to matching question types.
[moodle.git] / mod / lesson / backup / moodle1 / lib.php
1 <?php
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/>.
18 /**
19  * Provides support for the conversion of moodle1 backup to the moodle2 format
20  *
21  * @package    mod
22  * @subpackage lesson
23  * @copyright  2011 Rossiani Wijaya <rwijaya@moodle.com>
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
27 defined('MOODLE_INTERNAL') || die();
29 /**
30  * Lesson conversion handler
31  */
32 class moodle1_mod_lesson_handler extends moodle1_mod_handler {
33     // @var array of answers, when there are more that 4 answers, we need to fix <jumpto>.
34     protected $answers;
36     // @var stdClass a page object of the current page
37     protected $page;
38     // @var array of page objects to store entire pages, to help generate nextpageid and prevpageid in data
39     protected $pages;
40     // @var int a page id (previous)
41     protected $prevpageid = 0;
43     /** @var moodle1_file_manager */
44     protected $fileman = null;
46     /** @var int cmid */
47     protected $moduleid = null;
49     /**
50      * Declare the paths in moodle.xml we are able to convert
51      *
52      * The method returns list of {@link convert_path} instances.
53      * For each path returned, the corresponding conversion method must be
54      * defined.
55      *
56      * Note that the path /MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON does not
57      * actually exist in the file. The last element with the module name was
58      * appended by the moodle1_converter class.
59      *
60      * @return array of {@link convert_path} instances
61      */
62     public function get_paths() {
63         return array(
64             new convert_path(
65                 'lesson', '/MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON',
66                 array(
67                     'renamefields' => array(
68                         'usegrademax' => 'usemaxgrade',
69                     ),
70                 )
71             ),
72             new convert_path(
73                 'lesson_page', '/MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON/PAGES/PAGE',
74                 array(
75                     'newfields' => array(
76                         'contentsformat' => FORMAT_MOODLE,
77                         'nextpageid' => 0, //set to default to the next sequencial page in process_lesson_page()
78                         'prevpageid' => 0
79                     ),
80                 )
81             ),
82             new convert_path(
83                 'lesson_pages', '/MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON/PAGES'
84             ),
85             new convert_path(
86                 'lesson_answer', '/MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON/PAGES/PAGE/ANSWERS/ANSWER',
87                 array(
88                     'newfields' => array(
89                         'answerformat' => 0,
90                         'responseformat' => 0,
91                     ),
92                     'renamefields' => array(
93                         'answertext' => 'answer_text',
94                     ),
95                 )
96             )
97         );
98     }
100     /**
101      * This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON
102      * data available
103      */
104     public function process_lesson($data) {
106         // get the course module id and context id
107         $instanceid     = $data['id'];
108         $cminfo         = $this->get_cminfo($instanceid);
109         $this->moduleid = $cminfo['id'];
110         $contextid      = $this->converter->get_contextid(CONTEXT_MODULE, $this->moduleid);
112         // get a fresh new file manager for this instance
113         $this->fileman = $this->converter->get_file_manager($contextid, 'mod_lesson');
115         // migrate referenced local media files
116         if (!empty($data['mediafile']) and strpos($data['mediafile'], '://') === false) {
117             $this->fileman->filearea = 'mediafile';
118             $this->fileman->itemid   = 0;
119             try {
120                 $this->fileman->migrate_file('course_files/'.$data['mediafile']);
121             } catch (moodle1_convert_exception $e) {
122                 // the file probably does not exist
123                 $this->log('error migrating lesson mediafile', backup::LOG_WARNING, 'course_files/'.$data['mediafile']);
124             }
125         }
127         // start writing lesson.xml
128         $this->open_xml_writer("activities/lesson_{$this->moduleid}/lesson.xml");
129         $this->xmlwriter->begin_tag('activity', array('id' => $instanceid, 'moduleid' => $this->moduleid,
130             'modulename' => 'lesson', 'contextid' => $contextid));
131         $this->xmlwriter->begin_tag('lesson', array('id' => $instanceid));
133         foreach ($data as $field => $value) {
134             if ($field <> 'id') {
135                 $this->xmlwriter->full_tag($field, $value);
136             }
137         }
139         return $data;
140     }
142     public function on_lesson_pages_start() {
143         $this->xmlwriter->begin_tag('pages');
144     }
146     /**
147      * This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON/PAGES/PAGE
148      * data available
149      */
150     public function process_lesson_page($data) {
151         global $CFG;
153         // replay the upgrade step 2009120801
154         if ($CFG->texteditors !== 'textarea') {
155             $data['contents'] = text_to_html($data['contents'], false, false, true);
156             $data['contentsformat'] = FORMAT_HTML;
157         }
159         // store page in pages
160         $this->page = new stdClass();
161         $this->page->id = $data['pageid'];
162         unset($data['pageid']);
163         $this->page->data = $data;
164     }
166     /**
167      * This is executed every time we have one /MOODLE_BACKUP/COURSE/MODULES/MOD/LESSON/PAGES/PAGE/ANSWERS/ANSWER
168      * data available
169      */
170     public function process_lesson_answer($data) {
172         // replay the upgrade step 2010072003
173         $flags = intval($data['flags']);
174         if ($flags & 1) {
175             $data['answer_text']  = text_to_html($data['answer_text'], false, false, true);
176             $data['answerformat'] = FORMAT_HTML;
177         }
178         if ($flags & 2) {
179             $data['response']       = text_to_html($data['response'], false, false, true);
180             $data['responseformat'] = FORMAT_HTML;
181         }
183         // buffer for conversion of <jumpto> in line with
184         // upgrade step 2010121400 from mod/lesson/db/upgrade.php
185         $this->answers[] = $data;
186     }
188     public function on_lesson_page_end() {
189         $this->page->answers = $this->answers;
190         $this->pages[] = $this->page;
192         $firstbatch = count($this->pages) > 2;
193         $nextbatch = count($this->pages) > 1 && $this->prevpageid != 0;
195         if ( $firstbatch || $nextbatch ) { //we can write out 1 page atleast
196             if ($this->prevpageid == 0) {
197                 // start writing with n-2 page (relative to this on_lesson_page_end() call)
198                 $pg1 = $this->pages[1];
199                 $pg0 = $this->pages[0];
200                 $this->write_single_page_xml($pg0, 0, $pg1->id);
201                 $this->prevpageid = $pg0->id;
202                 array_shift($this->pages); //bye bye page0
203             }
205             $pg1 = $this->pages[0];
206             // write pg1 referencing prevpageid and pg2
207             $pg2 = $this->pages[1];
208             $this->write_single_page_xml($pg1, $this->prevpageid, $pg2->id);
209             $this->prevpageid = $pg1->id;
210             array_shift($this->pages); //throw written n-1th page
211         }
212         $this->answers = array(); //clear answers for the page ending. do not unset, object property will be missing.
213         $this->page = null;
214     }
216     public function on_lesson_pages_end() {
217         if ($this->pages) {
218             if (isset($this->pages[1])) { // write the case of only 2 pages.
219                 $this->write_single_page_xml($this->pages[0], $this->prevpageid, $this->pages[1]->id);
220                 $this->prevpageid = $this->pages[0]->id;
221                 array_shift($this->pages);
222             }
223             //write the remaining (first/last) single page
224             $this->write_single_page_xml($this->pages[0], $this->prevpageid, 0);
225         }
226         $this->xmlwriter->end_tag('pages');
227         //reset
228         unset($this->pages);
229         $this->prevpageid = 0;
231     }
233     /**
234      * This is executed when we reach the closing </MOD> tag of our 'lesson' path
235      */
236     public function on_lesson_end() {
237         // finish writing lesson.xml
238         $this->xmlwriter->end_tag('lesson');
239         $this->xmlwriter->end_tag('activity');
240         $this->close_xml_writer();
242         // write inforef.xml
243         $this->open_xml_writer("activities/lesson_{$this->moduleid}/inforef.xml");
244         $this->xmlwriter->begin_tag('inforef');
245         $this->xmlwriter->begin_tag('fileref');
246         foreach ($this->fileman->get_fileids() as $fileid) {
247             $this->write_xml('file', array('id' => $fileid));
248         }
249         $this->xmlwriter->end_tag('fileref');
250         $this->xmlwriter->end_tag('inforef');
251         $this->close_xml_writer();
252     }
254     /**
255      *  writes out the given page into the open xml handle
256      * @param type $page
257      * @param type $prevpageid
258      * @param type $nextpageid
259      */
260     protected function write_single_page_xml($page, $prevpageid=0, $nextpageid=0) {
261         //mince nextpageid and prevpageid
262         $page->data['nextpageid'] = $nextpageid;
263         $page->data['prevpageid'] = $prevpageid;
265         // write out each page data
266         $this->xmlwriter->begin_tag('page', array('id' => $page->id));
268         foreach ($page->data as $field => $value) {
269             $this->xmlwriter->full_tag($field, $value);
270         }
272         //effectively on_lesson_answers_end(), where we write out answers for current page.
273         $answers = $page->answers;
275         $this->xmlwriter->begin_tag('answers');
277         $numanswers = count($answers);
278         if ($numanswers) { //if there are any answers (possible there are none!)
279             if ($numanswers > 3 && $page->data['qtype'] == 5) { //fix only jumpto only for matching question types.
280                 if ($answers[0]['jumpto'] !== '0' || $answers[1]['jumpto'] !== '0') {
281                     if ($answers[2]['jumpto'] !== '0') {
282                         $answers[0]['jumpto'] = $answers[2]['jumpto'];
283                         $answers[2]['jumpto'] = '0';
284                     }
285                     if ($answers[3]['jumpto'] !== '0') {
286                         $answers[1]['jumpto'] = $answers[3]['jumpto'];
287                         $answers[3]['jumpto'] = '0';
288                     }
289                 }
290             }
291             foreach ($answers as $data) {
292                 $this->write_xml('answer', $data, array('/answer/id'));
293             }
294         }
296         $this->xmlwriter->end_tag('answers');
298         // answers is now closed for current page. Ending the page.
299         $this->xmlwriter->end_tag('page');
300     }