Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

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