Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  // This file is part of 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/>.
  16  /**
  17  * @package    backup-convert
  18  * @subpackage cc-library
  19  * @copyright  2011 Darko Miletic <dmiletic@moodlerooms.com>
  20  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  21  */
  22  
  23  if (!extension_loaded('fileinfo')) {
  24      die('You must install fileinfo extension!');
  25  }
  26  
  27  abstract class cc_convert_moodle2 {
  28  
  29      /**
  30       *
  31       * Enter description here ...
  32       * @param unknown_type $packagedir
  33       * @param unknown_type $outdir
  34       * @throws DOMException
  35       * @throws InvalidArgumentException
  36       */
  37      public static function convert($packagedir, $outdir) {
  38          $dir = realpath($packagedir);
  39          if (empty($dir)) {
  40              throw new InvalidArgumentException('Directory does not exist!');
  41          }
  42          $odir = realpath($outdir);
  43          if (empty($odir)) {
  44              throw new InvalidArgumentException('Directory does not exist!');
  45          }
  46          $coursefile = $dir.DIRECTORY_SEPARATOR.'course'.DIRECTORY_SEPARATOR.'course.xml';
  47          $doc = new XMLGenericDocument();
  48          if ($doc->load($coursefile)) {
  49              $course_name = $doc->nodeValue('/course/fullname');
  50              $course_desc = $doc->nodeValue('/course/summary');
  51              $course_language = $doc->nodeValue('/course/lang');
  52              $course_language = empty($course_language) ? 'en' : $course_language;
  53              $course_category = $doc->nodeValue('/course/category/name');
  54  
  55              //Initialize the manifest metadata class
  56              $meta = new cc_metadata_manifest();
  57  
  58              //Package metadata
  59              $metageneral = new cc_metadata_general();
  60              $metageneral->set_language($course_language);
  61              $metageneral->set_title($course_name, $course_language);
  62              $metageneral->set_description($course_desc, $course_language);
  63              $metageneral->set_catalog('category');
  64              $metageneral->set_entry($course_category);
  65              $meta->add_metadata_general($metageneral);
  66  
  67              // Create the manifest
  68              $manifest = new cc_manifest(cc_version::v11);
  69  
  70              $manifest->add_metadata_manifest($meta);
  71  
  72              $organization = null;
  73  
  74              //Package structure - default organization and resources
  75              //Get the course structure - this will be transformed into organization
  76              //Step 1 - Get the list and order of sections/topics
  77              $moodle_backup = $dir . DIRECTORY_SEPARATOR . 'moodle_backup.xml';
  78              $secp = new XMLGenericDocument();
  79              $docp = new XMLGenericDocument();
  80              if ($docp->load($moodle_backup)) {
  81                  //sections
  82                  $sections = array();
  83                  $coursef = new XMLGenericDocument();
  84                  $course_file = $dir . DIRECTORY_SEPARATOR .'course' . DIRECTORY_SEPARATOR . 'course.xml';
  85                  $coursef->load($course_file);
  86                  //$numsections = (int)$coursef->nodeValue('/course/numsections');
  87                  // TODO MDL-35781, this is commented because numsections is now optional attribute
  88                  $section_list = $docp->nodeList('/moodle_backup/information/contents/sections/section');
  89                  if (!empty($section_list)) {
  90                      $count = 0;
  91                      foreach ($section_list as $node) {
  92                          //if ($count > $numsections) {
  93                          //    break;
  94                          //}
  95                          $sectionid    = $docp->nodeValue('sectionid', $node);
  96                          $sectiontitle = $docp->nodeValue('title'    , $node);
  97                          $sectionpath  = $docp->nodeValue('directory', $node);
  98                          $sequence = array();
  99                          //Get section stuff
 100                          $section_file = $dir .
 101                          DIRECTORY_SEPARATOR .
 102                          $sectionpath .
 103                          DIRECTORY_SEPARATOR .
 104                          'section.xml';
 105                          if ($secp->load($section_file)) {
 106                              $rawvalue = $secp->nodeValue('/section/sequence');
 107                              if ($rawvalue != '$@NULL@$') {
 108                                  $sequence = explode(',', $rawvalue);
 109                              }
 110                          }
 111                          $sections[$sectionid] = array($sectiontitle, $sequence);
 112                          $count++;
 113                      }
 114                  }
 115                  //organization title
 116                  $organization = new cc_organization();
 117                  //Add section/topic items
 118                  foreach ($sections as $sectionid => $values) {
 119                      $item = new cc_item();
 120                      $item->title = $values[0];
 121                      self::process_sequence($item, $manifest, $values[1], $dir, $odir);
 122                      $organization->add_item($item);
 123                  }
 124                  $manifest->put_nodes();
 125              }
 126  
 127              if (!empty($organization)) {
 128                  $manifest->add_new_organization($organization);
 129              }
 130  
 131              $manifestpath = $outdir.DIRECTORY_SEPARATOR.'imsmanifest.xml';
 132              $manifest->saveTo($manifestpath);
 133          }
 134  
 135      }
 136  
 137      /**
 138      *
 139      * Process the activites and create item structure
 140      * @param cc_i_item $item
 141      * @param array $sequence
 142      * @param string $packageroot - directory path
 143      * @throws DOMException
 144      */
 145      protected static function process_sequence(cc_i_item &$item, cc_i_manifest &$manifest, array $sequence, $packageroot, $outdir) {
 146          $moodle_backup = $packageroot . DIRECTORY_SEPARATOR . 'moodle_backup.xml';
 147          $doc = new XMLGenericDocument();
 148          if(!$doc->load($moodle_backup)) {
 149              return;
 150          }
 151          $activities = $doc->nodeList('/moodle_backup/information/contents/activities/activity');
 152          if (!empty($activities)) {
 153              $dpp = new XMLGenericDocument();
 154              foreach ($activities as $activity) {
 155                  $moduleid = $doc->nodeValue('moduleid', $activity);
 156                  if (in_array($moduleid, $sequence)) {
 157                      //detect activity type
 158                      $directory = $doc->nodeValue('directory', $activity);
 159                      $path = $packageroot . DIRECTORY_SEPARATOR . $directory;
 160                      $module_file = $path . DIRECTORY_SEPARATOR . 'module.xml';
 161                      if ($dpp->load($module_file)) {
 162                          $activity_type = $dpp->nodeValue('/module/modulename');
 163                          $activity_indentation = $dpp->nodeValue('/module/indent');
 164                          $aitem = self::item_indenter($item, $activity_indentation);
 165                          $caller = "cc_converter_{$activity_type}";
 166                          if (class_exists($caller)) {
 167                              $obj = new $caller($aitem, $manifest, $packageroot, $path);
 168                              if (!$obj->convert($outdir)) {
 169                                  throw new RuntimeException("failed to convert {$activity_type}");
 170                              }
 171                          }
 172                      }
 173                  }
 174              }
 175          }
 176      }
 177  
 178      protected static function item_indenter(cc_i_item &$item, $level = 0) {
 179          $indent = (int)$level;
 180          $indent = ($indent) <= 0 ? 0 : $indent;
 181          $nprev = null;
 182          $nfirst = null;
 183          for ($pos = 0, $size = $indent; $pos < $size; $pos++) {
 184              $nitem = new cc_item();
 185              $nitem->title = '';
 186              if (empty($nfirst)) {
 187                  $nfirst = $nitem;
 188              }
 189              if (!empty($nprev)) {
 190                  $nprev->add_child_item($nitem);
 191              }
 192              $nprev = $nitem;
 193          }
 194          $result = $item;
 195          if (!empty($nfirst)) {
 196              $item->add_child_item($nfirst);
 197              $result = $nprev;
 198          }
 199          return $result;
 200      }
 201  
 202  }