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.

Differences Between: [Versions 401 and 402] [Versions 401 and 403]

   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  /**
  18   * @package    backup-convert
  19   * @subpackage cc-library
  20   * @copyright  2011 Darko Miletic <dmiletic@moodlerooms.com>
  21   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   */
  23  
  24  require_once ('cc_utils.php');
  25  require_once ('cc_version_base.php');
  26  require_once ('cc_organization.php');
  27  
  28  /**
  29   * Version 1 class of Common Cartridge
  30   *
  31   */
  32  class cc_version1 extends cc_version_base {
  33      const   webcontent          = 'webcontent';
  34      const   questionbank        = 'imsqti_xmlv1p2/imscc_xmlv1p0/question-bank';
  35      const   assessment          = 'imsqti_xmlv1p2/imscc_xmlv1p0/assessment';
  36      const   associatedcontent   = 'associatedcontent/imscc_xmlv1p0/learning-application-resource';
  37      const   discussiontopic     = 'imsdt_xmlv1p0';
  38      const   weblink             = 'imswl_xmlv1p0';
  39  
  40      public static $checker = array(self::webcontent,
  41                                     self::assessment,
  42                                     self::associatedcontent,
  43                                     self::discussiontopic,
  44                                     self::questionbank,
  45                                     self::weblink);
  46  
  47      /**
  48      * Validate if the type are valid or not
  49      *
  50      * @param string $type
  51      * @return bool
  52      */
  53      public function valid($type) {
  54          return in_array($type, self::$checker);
  55      }
  56  
  57      public function __construct() {
  58          $this->ccnamespaces     = array('imscc'    => 'http://www.imsglobal.org/xsd/imscc/imscp_v1p1',
  59                                          'lomimscc' => 'http://ltsc.ieee.org/xsd/imscc/LOM',
  60                                          'lom'      => 'http://ltsc.ieee.org/xsd/LOM',
  61                                          'voc'      => 'http://ltsc.ieee.org/xsd/LOM/vocab',
  62                                          'xsi'      => 'http://www.w3.org/2001/XMLSchema-instance'
  63                                          );
  64  
  65          $this->ccnsnames = array(
  66              'imscc'    => 'http://www.imsglobal.org/profile/cc/ccv1p0/derived_schema/imscp_v1p2_localised.xsd',
  67              'lom'      => 'http://www.imsglobal.org/profile/cc/ccv1p0/derived_schema/domainProfile_2/lomLoose_localised.xsd',
  68              'lomimscc' => 'http://www.imsglobal.org/profile/cc/ccv1p0/derived_schema/domainProfile_1/lomLoose_localised.xsd',
  69              'voc'      => 'http://www.imsglobal.org/profile/cc/ccv1p0/derived_schema/domainProfile_2/vocab/loose.xsd'
  70          );
  71  
  72          $this->ccversion        = '1.0.0';
  73          $this->camversion       = '1.0.0';
  74          $this->_generator       = 'Moodle 2 Common Cartridge generator';
  75      }
  76  
  77      protected function on_create(DOMDocument &$doc, $rootmanifestnode = null, $nmanifestID = null) {
  78          $doc->formatOutput       = true;
  79          $doc->preserveWhiteSpace = true;
  80  
  81  
  82          $this->manifestID = is_null($nmanifestID) ? cc_helpers::uuidgen('M_') : $nmanifestID;
  83          $mUUID            = $doc->createAttribute('identifier');
  84          $mUUID->nodeValue = $this->manifestID;
  85  
  86  
  87          if (is_null($rootmanifestnode)) {
  88              if (!empty($this->_generator)) {
  89                  $comment = $doc->createComment($this->_generator);
  90                  $doc->appendChild($comment);
  91              }
  92  
  93              $rootel = $doc->createElementNS($this->ccnamespaces['imscc'], 'manifest');
  94              $rootel->appendChild($mUUID);
  95              $doc->appendChild($rootel);
  96  
  97              // Add all namespaces.
  98              foreach ($this->ccnamespaces as $key => $value) {
  99                  $dummy_attr = $key.":dummy";
 100                  $doc->createAttributeNS($value, $dummy_attr);
 101              }
 102  
 103              // Add location of schemas.
 104              $schemaLocation = '';
 105              foreach ($this->ccnsnames as $key => $value) {
 106                  $vt = empty($schemaLocation) ? '' : ' ';
 107                  $schemaLocation .= $vt.$this->ccnamespaces[$key].' '.$value;
 108              }
 109              $aSchemaLoc            = $doc->createAttributeNS($this->ccnamespaces['xsi'], 'xsi:schemaLocation');
 110              $aSchemaLoc->nodeValue = $schemaLocation;
 111              $rootel->appendChild($aSchemaLoc);
 112  
 113          } else {
 114              $rootel = $doc->createElementNS($this->ccnamespaces['imscc'], 'imscc:manifest');
 115              $rootel->appendChild($mUUID);
 116          }
 117  
 118          $metadata      = $doc->createElementNS($this->ccnamespaces['imscc'], 'metadata');
 119          $schema        = $doc->createElementNS($this->ccnamespaces['imscc'], 'schema', 'IMS Common Cartridge');
 120          $schemaversion = $doc->createElementNS($this->ccnamespaces['imscc'], 'schemaversion', $this->ccversion);
 121  
 122          $metadata->appendChild($schema);
 123          $metadata->appendChild($schemaversion);
 124          $rootel->appendChild($metadata);
 125  
 126          if (!is_null($rootmanifestnode)) {
 127              $rootmanifestnode->appendChild($rootel);
 128          }
 129  
 130          $organizations = $doc->createElementNS($this->ccnamespaces['imscc'], 'organizations');
 131          $rootel->appendChild($organizations);
 132          $resources = $doc->createElementNS($this->ccnamespaces['imscc'], 'resources');
 133          $rootel->appendChild($resources);
 134  
 135          return true;
 136      }
 137  
 138      protected function update_attribute(DOMDocument &$doc, $attrname, $attrvalue, DOMElement &$node) {
 139          $busenew = (is_object($node) && $node->hasAttribute($attrname));
 140          $nResult = null;
 141          if (!$busenew && is_null($attrvalue)) {
 142              $node->removeAttribute($attrname);
 143          } else {
 144              $nResult = $busenew ? $node->getAttributeNode($attrname) : $doc->createAttribute($attrname);
 145              $nResult->nodeValue = $attrvalue;
 146              if (!$busenew) {
 147                  $node->appendChild($nResult);
 148              }
 149          }
 150          return $nResult;
 151      }
 152  
 153      protected function update_attribute_ns(DOMDocument &$doc, $attrname, $attrnamespace,$attrvalue, DOMElement &$node) {
 154          $busenew = (is_object($node) && $node->hasAttributeNS($attrnamespace, $attrname));
 155          $nResult = null;
 156          if (!$busenew && is_null($attrvalue)) {
 157              $node->removeAttributeNS($attrnamespace, $attrname);
 158          } else {
 159              $nResult = $busenew ? $node->getAttributeNodeNS($attrnamespace, $attrname) :
 160                  $doc->createAttributeNS($attrnamespace, $attrname);
 161              $nResult->nodeValue = $attrvalue;
 162              if (!$busenew) {
 163                  $node->appendChild($nResult);
 164              }
 165          }
 166          return $nResult;
 167      }
 168  
 169      protected function get_child_node(DOMDocument &$doc, $itemname, DOMElement &$node) {
 170          $nlist = $node->getElementsByTagName($itemname);
 171          $item = is_object($nlist) && ($nlist->length > 0) ? $nlist->item(0) : null;
 172          return $item;
 173      }
 174  
 175      protected function update_child_item(DOMDocument &$doc, $itemname, $itemvalue, DOMElement &$node, $attrtostore=null) {
 176          $tnode = $this->get_child_node($doc, 'title', $node);
 177          $usenew = is_null($tnode);
 178          $tnode = $usenew ? $doc->createElementNS($this->ccnamespaces['imscc'], $itemname) : $tnode;
 179          if (!is_null($attrtostore)) {
 180              foreach ($attrtostore as $key => $value) {
 181                  $this->update_attribute($doc, $key, $value, $tnode);
 182              }
 183          }
 184          $tnode->nodeValue = $itemvalue;
 185          if ($usenew) {
 186              $node->appendChild($tnode);
 187          }
 188      }
 189  
 190      protected function update_items($items, DOMDocument &$doc, DOMElement &$xmlnode) {
 191          foreach ($items as $key => $item) {
 192              $itemnode = $doc->createElementNS($this->ccnamespaces['imscc'], 'item');
 193              $this->update_attribute($doc, 'identifier'   , $key                , $itemnode);
 194              $this->update_attribute($doc, 'identifierref', $item->identifierref, $itemnode);
 195              $this->update_attribute($doc, 'parameters'   , $item->parameters   , $itemnode);
 196              if (!empty($item->title)) {
 197                  $titlenode = $doc->createElementNS($this->ccnamespaces['imscc'],
 198                                                     'title',
 199                                                     $item->title);
 200                  $itemnode->appendChild($titlenode);
 201              }
 202              if ($item->has_child_items()) {
 203                  $this->update_items($item->childitems, $doc, $itemnode);
 204              }
 205              $xmlnode->appendChild($itemnode);
 206          }
 207      }
 208  
 209      /**
 210       * Create a Resource (How to)
 211       *
 212       * @param cc_i_resource $res
 213       * @param DOMDocument $doc
 214       * @param object $xmlnode
 215       * @return DOMNode
 216       */
 217      protected function create_resource(cc_i_resource &$res, DOMDocument &$doc, $xmlnode=null) {
 218          $usenew = is_object($xmlnode);
 219          $dnode  = $usenew ? $xmlnode : $doc->createElementNS($this->ccnamespaces['imscc'], "resource");
 220          $this->update_attribute($doc, 'identifier', $res->identifier, $dnode);
 221          $this->update_attribute($doc, 'type', $res->type, $dnode);
 222          !is_null($res->href) ? $this->update_attribute($doc, 'href', $res->href, $dnode) : null;
 223          $this->update_attribute($doc, 'base', $res->base, $dnode);
 224  
 225          foreach ($res->files as $file) {
 226              $nd = $doc->createElementNS($this->ccnamespaces['imscc'], 'file');
 227              $ndatt = $doc->createAttribute('href');
 228              $ndatt->nodeValue = $file;
 229              $nd->appendChild($ndatt);
 230              $dnode->appendChild($nd);
 231          }
 232          $this->resources[$res->identifier]   = $res;
 233          $this->resources_ind[$res->files[0]] = $res->identifier;
 234  
 235          foreach ($res->dependency as $dependency) {
 236              $nd = $doc->createElementNS($this->ccnamespaces['imscc'], 'dependency');
 237              $ndatt = $doc->createAttribute('identifierref');
 238              $ndatt->nodeValue = $dependency;
 239              $nd->appendChild($ndatt);
 240              $dnode->appendChild($nd);
 241          }
 242  
 243          return $dnode;
 244      }
 245  
 246      /**
 247       * Create an Item Folder (How To)
 248       *
 249       * @param cc_i_organization $org
 250       * @param DOMDocument $doc
 251       * @param DOMElement $xmlnode
 252       */
 253      protected function create_item_folder(cc_i_organization &$org, DOMDocument &$doc, DOMElement &$xmlnode = null) {
 254  
 255          $itemfoldernode = $doc->createElementNS($this->ccnamespaces['imscc'], 'item');
 256          $this->update_attribute($doc, 'identifier', "root", $itemfoldernode);
 257  
 258          if ($org->has_items()) {
 259              $this->update_items($org->itemlist, $doc, $itemfoldernode);
 260          }
 261          if (is_null($this->organizations)) {
 262              $this->organizations = array();
 263          }
 264          $this->organizations[$org->identifier] = $org;
 265  
 266          $xmlnode->appendChild($itemfoldernode);
 267      }
 268  
 269      /**
 270       * Create an Organization (How To)
 271       *
 272       * @param cc_i_organization $org
 273       * @param DOMDocument $doc
 274       * @param object $xmlnode
 275       * @return DOMNode
 276       */
 277      protected function create_organization(cc_i_organization &$org, DOMDocument &$doc, $xmlnode = null) {
 278  
 279          $usenew = is_object($xmlnode);
 280          $dnode  = $usenew ? $xmlnode : $doc->createElementNS($this->ccnamespaces['imscc'], "organization");
 281          $this->update_attribute($doc, 'identifier', $org->identifier, $dnode);
 282          $this->update_attribute($doc, 'structure', $org->structure, $dnode);
 283  
 284          $this->create_item_folder($org, $doc, $dnode);
 285  
 286          return $dnode;
 287      }
 288  
 289      /**
 290       * Create Metadata For Manifest (How To)
 291       *
 292       * @param cc_i_metadata_manifest $met
 293       * @param DOMDocument $doc
 294       * @param object $xmlnode
 295       * @return DOMNode
 296       */
 297      protected function create_metadata_manifest(cc_i_metadata_manifest $met, DOMDocument &$doc, $xmlnode = null) {
 298  
 299          $dnode = $doc->createElementNS($this->ccnamespaces['lomimscc'], "lom");
 300          if (!empty($xmlnode)) {
 301              $xmlnode->appendChild($dnode);
 302          }
 303          $dnodegeneral   = empty($met->arraygeneral) ? null : $this->create_metadata_general($met, $doc, $xmlnode);
 304          $dnodetechnical = empty($met->arraytech) ? null : $this->create_metadata_technical($met, $doc, $xmlnode);
 305          $dnoderights    = empty($met->arrayrights) ? null : $this->create_metadata_rights($met, $doc, $xmlnode);
 306          $dnodelifecycle = empty($met->arraylifecycle) ? null : $this->create_metadata_lifecycle($met, $doc, $xmlnode);
 307  
 308          !is_null($dnodegeneral) ? $dnode->appendChild($dnodegeneral) : null;
 309          !is_null($dnodetechnical) ? $dnode->appendChild($dnodetechnical) : null;
 310          !is_null($dnoderights) ? $dnode->appendChild($dnoderights) : null;
 311          !is_null($dnodelifecycle) ? $dnode->appendChild($dnodelifecycle) : null;
 312  
 313          return $dnode;
 314  
 315      }
 316  
 317      /**
 318       * Create Metadata For Resource (How To)
 319       *
 320       * @param cc_i_metadata_resource $met
 321       * @param DOMDocument $doc
 322       * @param object $xmlnode
 323       * @return DOMNode
 324       */
 325      protected function create_metadata_resource(cc_i_metadata_resource $met, DOMDocument &$doc, $xmlnode = null) {
 326  
 327          $dnode = $doc->createElementNS($this->ccnamespaces['lom'], "lom");
 328  
 329          !empty($xmlnode) ? $xmlnode->appendChild($dnode) : null;
 330          !empty($met->arrayeducational) ? $this->create_metadata_educational($met, $doc, $dnode) : null;
 331  
 332          return $dnode;
 333      }
 334  
 335      /**
 336       * Create Metadata For File (How To)
 337       *
 338       * @param cc_i_metadata_file $met
 339       * @param DOMDocument $doc
 340       * @param Object $xmlnode
 341       * @return DOMNode
 342       */
 343      protected function create_metadata_file(cc_i_metadata_file $met, DOMDocument &$doc, $xmlnode = null) {
 344  
 345          $dnode = $doc->createElementNS($this->ccnamespaces['lom'], "lom");
 346  
 347          !empty($xmlnode) ? $xmlnode->appendChild($dnode) : null;
 348          !empty($met->arrayeducational) ? $this->create_metadata_educational($met, $doc, $dnode) : null;
 349  
 350          return $dnode;
 351      }
 352  
 353      /**
 354       * Create General Metadata (How To)
 355       *
 356       * @param object $met
 357       * @param DOMDocument $doc
 358       * @param object $xmlnode
 359       * @return DOMNode
 360       */
 361      protected function create_metadata_general($met, DOMDocument &$doc, $xmlnode) {
 362          $nd = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'general');
 363  
 364          foreach ($met->arraygeneral as $name => $value) {
 365              !is_array($value) ? $value = array($value) : null;
 366              foreach ($value as $v) {
 367                  if ($name != 'language' && $name != 'catalog' && $name != 'entry') {
 368                      $nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name);
 369                      $nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'string', $v[1]);
 370                      $ndatt = $doc->createAttribute('language');
 371                      $ndatt->nodeValue = $v[0];
 372                      $nd3->appendChild($ndatt);
 373                      $nd2->appendChild($nd3);
 374                      $nd->appendChild($nd2);
 375                  } else {
 376                      if ($name == 'language') {
 377                          $nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name, $v[0]);
 378                          $nd->appendChild($nd2);
 379                      }
 380                  }
 381              }
 382          }
 383          if (!empty($met->arraygeneral['catalog']) || !empty($met->arraygeneral['entry'])) {
 384              $nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'identifier');
 385              $nd->appendChild($nd2);
 386              if (!empty($met->arraygeneral['catalog'])) {
 387                  $nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'catalog', $met->arraygeneral['catalog'][0][0]);
 388                  $nd2->appendChild($nd3);
 389              }
 390              if (!empty($met->arraygeneral['entry'])) {
 391                  $nd4 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'entry', $met->arraygeneral['entry'][0][0]);
 392                  $nd2->appendChild($nd4);
 393              }
 394          }
 395          return $nd;
 396      }
 397  
 398      /**
 399       * Create Technical Metadata (How To)
 400       *
 401       * @param object $met
 402       * @param DOMDocument $doc
 403       * @param object $xmlnode
 404       * @return DOMNode
 405       */
 406      protected function create_metadata_technical($met, DOMDocument &$doc, $xmlnode) {
 407          $nd = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'technical');
 408          $xmlnode->appendChild($nd);
 409  
 410          foreach ($met->arraytech as $name => $value) {
 411              !is_array($value) ? $value = array($value) : null;
 412              foreach ($value as $v) {
 413                  $nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name, $v[0]);
 414                  $nd->appendChild($nd2);
 415              }
 416          }
 417          return $nd;
 418      }
 419  
 420  
 421      /**
 422       * Create Rights Metadata (How To)
 423       *
 424       * @param object $met
 425       * @param DOMDocument $doc
 426       * @param object $xmlnode
 427       * @return DOMNode
 428       */
 429      protected function create_metadata_rights($met, DOMDocument &$doc, $xmlnode) {
 430  
 431          $nd = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'rights');
 432  
 433          foreach ($met->arrayrights as $name => $value) {
 434              !is_array($value) ? $value = array($value) : null;
 435              foreach ($value as $v) {
 436                  if ($name == 'description') {
 437                      $nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name);
 438                      $nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'string', $v[1]);
 439                      $ndatt = $doc->createAttribute('language');
 440                      $ndatt->nodeValue = $v[0];
 441                      $nd3->appendChild($ndatt);
 442                      $nd2->appendChild($nd3);
 443                      $nd->appendChild($nd2);
 444                  } else if ($name == 'copyrightAndOtherRestrictions' || $name == 'cost') {
 445                      $nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name);
 446                      $nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'value', $v[0]);
 447                      $nd2->appendChild($nd3);
 448                      $nd->appendChild($nd2);
 449                  }
 450              }
 451          }
 452          return $nd;
 453      }
 454  
 455      /**
 456       * Create Lifecycle Metadata (How To)
 457       *
 458       * @param object $met
 459       * @param DOMDocument $doc
 460       * @param object $xmlnode
 461       * @return DOMNode
 462       */
 463      protected function create_metadata_lifecycle($met, DOMDocument &$doc, $xmlnode) {
 464  
 465          $nd  = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'lifeCycle');
 466          $nd2 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'contribute');
 467  
 468          $nd->appendChild($nd2);
 469          $xmlnode->appendChild($nd);
 470  
 471          foreach ($met->arraylifecycle as $name => $value) {
 472              !is_array($value) ? $value = array($value) : null;
 473              foreach ($value as $v) {
 474                  if ($name == 'role') {
 475                      $nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name);
 476                      $nd2->appendChild($nd3);
 477                      $nd4 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'value', $v[0]);
 478                      $nd3->appendChild($nd4);
 479                  } else {
 480                      if ($name == 'date') {
 481                          $nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name);
 482                          $nd2->appendChild($nd3);
 483                          $nd4 = $doc->createElementNS($this->ccnamespaces['lomimscc'], 'dateTime', $v[0]);
 484                          $nd3->appendChild($nd4);
 485                      } else {
 486                          $nd3 = $doc->createElementNS($this->ccnamespaces['lomimscc'], $name, $v[0]);
 487                          $nd2->appendChild($nd3);
 488                      }
 489                  }
 490              }
 491          }
 492          return $nd;
 493      }
 494  
 495      /**
 496       * Create Education Metadata (How To)
 497       *
 498       * @param object $met
 499       * @param DOMDocument $doc
 500       * @param object $xmlnode
 501       * @return DOMNode
 502       */
 503      public function create_metadata_educational($met, DOMDocument  &$doc, $xmlnode) {
 504          $nd  = $doc->createElementNS($this->ccnamespaces['lom'], 'educational');
 505          $nd2 = $doc->createElementNS($this->ccnamespaces['lom'], 'intendedEndUserRole');
 506          $nd3 = $doc->createElementNS($this->ccnamespaces['voc'], 'vocabulary');
 507  
 508          $xmlnode->appendChild($nd);
 509          $nd->appendChild($nd2);
 510          $nd2->appendChild($nd3);
 511  
 512          foreach ($met->arrayeducational as $name => $value) {
 513              !is_array($value) ? $value = array($value) : null;
 514              foreach ($value as $v) {
 515                  $nd4 = $doc->createElementNS($this->ccnamespaces['voc'], $name, $v[0]);
 516                  $nd3->appendChild($nd4);
 517              }
 518          }
 519          return $nd;
 520      }
 521  }