Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]

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