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 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [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   * SCORM module external API
  19   *
  20   * @package    mod_scorm
  21   * @category   external
  22   * @copyright  2015 Juan Leyva <juan@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   * @since      Moodle 3.0
  25   */
  26  
  27  use core_course\external\helper_for_get_mods_by_courses;
  28  
  29  defined('MOODLE_INTERNAL') || die;
  30  
  31  require_once($CFG->libdir . '/externallib.php');
  32  require_once($CFG->dirroot . '/mod/scorm/lib.php');
  33  require_once($CFG->dirroot . '/mod/scorm/locallib.php');
  34  
  35  /**
  36   * SCORM module external functions
  37   *
  38   * @package    mod_scorm
  39   * @category   external
  40   * @copyright  2015 Juan Leyva <juan@moodle.com>
  41   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  42   * @since      Moodle 3.0
  43   */
  44  class mod_scorm_external extends external_api {
  45  
  46      /**
  47       * Returns description of method parameters
  48       *
  49       * @return external_function_parameters
  50       * @since Moodle 3.0
  51       */
  52      public static function view_scorm_parameters() {
  53          return new external_function_parameters(
  54              array(
  55                  'scormid' => new external_value(PARAM_INT, 'scorm instance id')
  56              )
  57          );
  58      }
  59  
  60      /**
  61       * Trigger the course module viewed event.
  62       *
  63       * @param int $scormid the scorm instance id
  64       * @return array of warnings and status result
  65       * @since Moodle 3.0
  66       * @throws moodle_exception
  67       */
  68      public static function view_scorm($scormid) {
  69          global $DB, $CFG;
  70          require_once($CFG->dirroot . '/mod/scorm/lib.php');
  71  
  72          $params = self::validate_parameters(self::view_scorm_parameters(),
  73                                              array(
  74                                                  'scormid' => $scormid
  75                                              ));
  76          $warnings = array();
  77  
  78          // Request and permission validation.
  79          $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
  80          list($course, $cm) = get_course_and_cm_from_instance($scorm, 'scorm');
  81  
  82          $context = context_module::instance($cm->id);
  83          self::validate_context($context);
  84  
  85          // Call the scorm/lib API.
  86          scorm_view($scorm, $course, $cm, $context);
  87  
  88          $result = array();
  89          $result['status'] = true;
  90          $result['warnings'] = $warnings;
  91          return $result;
  92      }
  93  
  94      /**
  95       * Returns description of method result value
  96       *
  97       * @return external_description
  98       * @since Moodle 3.0
  99       */
 100      public static function view_scorm_returns() {
 101          return new external_single_structure(
 102              array(
 103                  'status' => new external_value(PARAM_BOOL, 'status: true if success'),
 104                  'warnings' => new external_warnings()
 105              )
 106          );
 107      }
 108  
 109      /**
 110       * Describes the parameters for get_scorm_attempt_count.
 111       *
 112       * @return external_function_parameters
 113       * @since Moodle 3.0
 114       */
 115      public static function get_scorm_attempt_count_parameters() {
 116          return new external_function_parameters(
 117              array(
 118                  'scormid' => new external_value(PARAM_INT, 'SCORM instance id'),
 119                  'userid' => new external_value(PARAM_INT, 'User id'),
 120                  'ignoremissingcompletion' => new external_value(PARAM_BOOL,
 121                                                  'Ignores attempts that haven\'t reported a grade/completion',
 122                                                  VALUE_DEFAULT, false),
 123              )
 124          );
 125      }
 126  
 127      /**
 128       * Return the number of attempts done by a user in the given SCORM.
 129       *
 130       * @param int $scormid the scorm id
 131       * @param int $userid the user id
 132       * @param bool $ignoremissingcompletion ignores attempts that haven't reported a grade/completion
 133       * @return array of warnings and the attempts count
 134       * @since Moodle 3.0
 135       */
 136      public static function get_scorm_attempt_count($scormid, $userid, $ignoremissingcompletion = false) {
 137          global $USER, $DB;
 138  
 139          $params = self::validate_parameters(self::get_scorm_attempt_count_parameters(),
 140                                              array('scormid' => $scormid, 'userid' => $userid,
 141                                                  'ignoremissingcompletion' => $ignoremissingcompletion));
 142  
 143          $attempts = array();
 144          $warnings = array();
 145  
 146          $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
 147          $cm = get_coursemodule_from_instance('scorm', $scorm->id);
 148  
 149          $context = context_module::instance($cm->id);
 150          self::validate_context($context);
 151  
 152          $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
 153          core_user::require_active_user($user);
 154  
 155          // Extra checks so only users with permissions can view other users attempts.
 156          if ($USER->id != $user->id) {
 157              require_capability('mod/scorm:viewreport', $context);
 158          }
 159  
 160          // If the SCORM is not open this function will throw exceptions.
 161          scorm_require_available($scorm);
 162  
 163          $attemptscount = scorm_get_attempt_count($user->id, $scorm, false, $params['ignoremissingcompletion']);
 164  
 165          $result = array();
 166          $result['attemptscount'] = $attemptscount;
 167          $result['warnings'] = $warnings;
 168          return $result;
 169      }
 170  
 171      /**
 172       * Describes the get_scorm_attempt_count return value.
 173       *
 174       * @return external_single_structure
 175       * @since Moodle 3.0
 176       */
 177      public static function get_scorm_attempt_count_returns() {
 178  
 179          return new external_single_structure(
 180              array(
 181                  'attemptscount' => new external_value(PARAM_INT, 'Attempts count'),
 182                  'warnings' => new external_warnings(),
 183              )
 184          );
 185      }
 186  
 187      /**
 188       * Describes the parameters for get_scorm_scoes.
 189       *
 190       * @return external_function_parameters
 191       * @since Moodle 3.0
 192       */
 193      public static function get_scorm_scoes_parameters() {
 194          return new external_function_parameters(
 195              array(
 196                  'scormid' => new external_value(PARAM_INT, 'scorm instance id'),
 197                  'organization' => new external_value(PARAM_RAW, 'organization id', VALUE_DEFAULT, '')
 198              )
 199          );
 200      }
 201  
 202      /**
 203       * Returns a list containing all the scoes data related to the given scorm id
 204       *
 205       * @param int $scormid the scorm id
 206       * @param string $organization the organization id
 207       * @return array warnings and the scoes data
 208       * @since Moodle 3.0
 209       */
 210      public static function get_scorm_scoes($scormid, $organization = '') {
 211          global $DB;
 212  
 213          $params = self::validate_parameters(self::get_scorm_scoes_parameters(),
 214                                              array('scormid' => $scormid, 'organization' => $organization));
 215  
 216          $scoes = array();
 217          $warnings = array();
 218  
 219          $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
 220          $cm = get_coursemodule_from_instance('scorm', $scorm->id);
 221  
 222          $context = context_module::instance($cm->id);
 223          self::validate_context($context);
 224  
 225          // Check settings / permissions to view the SCORM.
 226          scorm_require_available($scorm, true, $context);
 227  
 228          if (!$scoes = scorm_get_scoes($scorm->id, $params['organization'])) {
 229              // Function scorm_get_scoes return false, not an empty array.
 230              $scoes = array();
 231          } else {
 232              $scoreturnstructure = self::get_scorm_scoes_returns();
 233              foreach ($scoes as $sco) {
 234                  $extradata = array();
 235                  foreach ($sco as $element => $value) {
 236                      // Check if the element is extra data (not a basic SCO element).
 237                      if (!isset($scoreturnstructure->keys['scoes']->content->keys[$element])) {
 238                          $extradata[] = array(
 239                              'element' => $element,
 240                              'value' => $value
 241                          );
 242                      }
 243                  }
 244                  $sco->extradata = $extradata;
 245              }
 246          }
 247  
 248          $result = array();
 249          $result['scoes'] = $scoes;
 250          $result['warnings'] = $warnings;
 251          return $result;
 252      }
 253  
 254      /**
 255       * Describes the get_scorm_scoes return value.
 256       *
 257       * @return external_single_structure
 258       * @since Moodle 3.0
 259       */
 260      public static function get_scorm_scoes_returns() {
 261  
 262          return new external_single_structure(
 263              array(
 264                  'scoes' => new external_multiple_structure(
 265                      new external_single_structure(
 266                          array(
 267                              'id' => new external_value(PARAM_INT, 'sco id'),
 268                              'scorm' => new external_value(PARAM_INT, 'scorm id'),
 269                              'manifest' => new external_value(PARAM_NOTAGS, 'manifest id'),
 270                              'organization' => new external_value(PARAM_NOTAGS, 'organization id'),
 271                              'parent' => new external_value(PARAM_NOTAGS, 'parent'),
 272                              'identifier' => new external_value(PARAM_NOTAGS, 'identifier'),
 273                              'launch' => new external_value(PARAM_NOTAGS, 'launch file'),
 274                              'scormtype' => new external_value(PARAM_ALPHA, 'scorm type (asset, sco)'),
 275                              'title' => new external_value(PARAM_NOTAGS, 'sco title'),
 276                              'sortorder' => new external_value(PARAM_INT, 'sort order'),
 277                              'extradata' => new external_multiple_structure(
 278                                  new external_single_structure(
 279                                      array(
 280                                          'element' => new external_value(PARAM_RAW, 'element name'),
 281                                          'value' => new external_value(PARAM_RAW, 'element value')
 282                                      )
 283                                  ), 'Additional SCO data', VALUE_OPTIONAL
 284                              )
 285                          ), 'SCORM SCO data'
 286                      )
 287                  ),
 288                  'warnings' => new external_warnings(),
 289              )
 290          );
 291      }
 292  
 293      /**
 294       * Describes the parameters for get_scorm_user_data.
 295       *
 296       * @return external_function_parameters
 297       * @since Moodle 3.0
 298       */
 299      public static function get_scorm_user_data_parameters() {
 300          return new external_function_parameters(
 301              array(
 302                  'scormid' => new external_value(PARAM_INT, 'scorm instance id'),
 303                  'attempt' => new external_value(PARAM_INT, 'attempt number')
 304              )
 305          );
 306      }
 307  
 308      /**
 309       * Retrieves user tracking and SCO data and default SCORM values
 310       *
 311       * @param int $scormid the scorm id
 312       * @param int $attempt the attempt number
 313       * @return array warnings and the scoes data
 314       * @throws  moodle_exception
 315       * @since Moodle 3.0
 316       */
 317      public static function get_scorm_user_data($scormid, $attempt) {
 318          global $CFG, $DB;
 319  
 320          $params = self::validate_parameters(self::get_scorm_user_data_parameters(),
 321                                              array('scormid' => $scormid, 'attempt' => $attempt));
 322  
 323          $data = array();
 324          $warnings = array();
 325  
 326          $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
 327          $cm = get_coursemodule_from_instance('scorm', $scorm->id);
 328  
 329          $context = context_module::instance($cm->id);
 330          self::validate_context($context);
 331  
 332          scorm_require_available($scorm, true, $context);
 333  
 334          $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR));
 335          if (!file_exists($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'lib.php')) {
 336              $scorm->version = 'scorm_12';
 337          }
 338          require_once($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'lib.php');
 339  
 340          if ($scoes = scorm_get_scoes($scorm->id)) {
 341              $def = new stdClass();
 342              $user = new stdClass();
 343  
 344              foreach ($scoes as $sco) {
 345                  $def->{$sco->id} = new stdClass();
 346                  $user->{$sco->id} = new stdClass();
 347                  // We force mode normal, this can be override by the client at any time.
 348                  $def->{$sco->id} = get_scorm_default($user->{$sco->id}, $scorm, $sco->id, $params['attempt'], 'normal');
 349  
 350                  $userdata = array();
 351                  $defaultdata = array();
 352  
 353                  foreach ((array) $user->{$sco->id} as $key => $val) {
 354                      $userdata[] = array(
 355                          'element' => $key,
 356                          'value' => $val
 357                      );
 358                  }
 359                  foreach ($def->{$sco->id} as $key => $val) {
 360                      $defaultdata[] = array(
 361                          'element' => $key,
 362                          'value' => $val
 363                      );
 364                  }
 365  
 366                  $data[] = array(
 367                      'scoid' => $sco->id,
 368                      'userdata' => $userdata,
 369                      'defaultdata' => $defaultdata,
 370                  );
 371              }
 372          }
 373  
 374          $result = array();
 375          $result['data'] = $data;
 376          $result['warnings'] = $warnings;
 377          return $result;
 378      }
 379  
 380      /**
 381       * Describes the get_scorm_user_data return value.
 382       *
 383       * @return external_single_structure
 384       * @since Moodle 3.0
 385       */
 386      public static function get_scorm_user_data_returns() {
 387  
 388          return new external_single_structure(
 389              array(
 390                  'data' => new external_multiple_structure(
 391                      new external_single_structure(
 392                          array(
 393                              'scoid' => new external_value(PARAM_INT, 'sco id'),
 394                              'userdata' => new external_multiple_structure(
 395                                              new external_single_structure(
 396                                                  array(
 397                                                      'element' => new external_value(PARAM_RAW, 'element name'),
 398                                                      'value' => new external_value(PARAM_RAW, 'element value')
 399                                                  )
 400                                              )
 401                                            ),
 402                              'defaultdata' => new external_multiple_structure(
 403                                                  new external_single_structure(
 404                                                      array(
 405                                                          'element' => new external_value(PARAM_RAW, 'element name'),
 406                                                          'value' => new external_value(PARAM_RAW, 'element value')
 407                                                      )
 408                                                  )
 409                                               ),
 410                          ), 'SCO data'
 411                      )
 412                  ),
 413                  'warnings' => new external_warnings(),
 414              )
 415          );
 416      }
 417  
 418      /**
 419       * Describes the parameters for insert_scorm_tracks.
 420       *
 421       * @return external_function_parameters
 422       * @since Moodle 3.0
 423       */
 424      public static function insert_scorm_tracks_parameters() {
 425          return new external_function_parameters(
 426              array(
 427                  'scoid' => new external_value(PARAM_INT, 'SCO id'),
 428                  'attempt' => new external_value(PARAM_INT, 'attempt number'),
 429                  'tracks' => new external_multiple_structure(
 430                      new external_single_structure(
 431                          array(
 432                              'element' => new external_value(PARAM_RAW, 'element name'),
 433                              'value' => new external_value(PARAM_RAW, 'element value')
 434                          )
 435                      )
 436                  ),
 437              )
 438          );
 439      }
 440  
 441      /**
 442       * Saves a SCORM tracking record.
 443       * It will overwrite any existing tracking data for this attempt.
 444       * Validation should be performed before running the function to ensure the user will not lose any existing attempt data.
 445       *
 446       * @param int $scoid the SCO id
 447       * @param string $attempt the attempt number
 448       * @param array $tracks the track records to be stored
 449       * @return array warnings and the scoes data
 450       * @throws moodle_exception
 451       * @since Moodle 3.0
 452       */
 453      public static function insert_scorm_tracks($scoid, $attempt, $tracks) {
 454          global $USER, $DB;
 455  
 456          $params = self::validate_parameters(self::insert_scorm_tracks_parameters(),
 457                                              array('scoid' => $scoid, 'attempt' => $attempt, 'tracks' => $tracks));
 458  
 459          $trackids = array();
 460          $warnings = array();
 461  
 462          $sco = scorm_get_sco($params['scoid'], SCO_ONLY);
 463          if (!$sco) {
 464              throw new moodle_exception('cannotfindsco', 'scorm');
 465          }
 466  
 467          $scorm = $DB->get_record('scorm', array('id' => $sco->scorm), '*', MUST_EXIST);
 468          $cm = get_coursemodule_from_instance('scorm', $scorm->id);
 469  
 470          $context = context_module::instance($cm->id);
 471          self::validate_context($context);
 472  
 473          // Check settings / permissions to view the SCORM.
 474          require_capability('mod/scorm:savetrack', $context);
 475  
 476          // Check settings / permissions to view the SCORM.
 477          scorm_require_available($scorm);
 478  
 479          foreach ($params['tracks'] as $track) {
 480              $element = $track['element'];
 481              $value = $track['value'];
 482              $trackid = scorm_insert_track($USER->id, $scorm->id, $sco->id, $params['attempt'], $element, $value,
 483                                              $scorm->forcecompleted);
 484  
 485              if ($trackid) {
 486                  $trackids[] = $trackid;
 487              } else {
 488                  $warnings[] = array(
 489                      'item' => 'scorm',
 490                      'itemid' => $scorm->id,
 491                      'warningcode' => 1,
 492                      'message' => 'Element: ' . $element . ' was not saved'
 493                  );
 494              }
 495          }
 496  
 497          $result = array();
 498          $result['trackids'] = $trackids;
 499          $result['warnings'] = $warnings;
 500          return $result;
 501      }
 502  
 503      /**
 504       * Describes the insert_scorm_tracks return value.
 505       *
 506       * @return external_single_structure
 507       * @since Moodle 3.0
 508       */
 509      public static function insert_scorm_tracks_returns() {
 510  
 511          return new external_single_structure(
 512              array(
 513                  'trackids' => new external_multiple_structure(new external_value(PARAM_INT, 'track id')),
 514                  'warnings' => new external_warnings(),
 515              )
 516          );
 517      }
 518  
 519      /**
 520       * Describes the parameters for get_scorm_sco_tracks.
 521       *
 522       * @return external_function_parameters
 523       * @since Moodle 3.0
 524       */
 525      public static function get_scorm_sco_tracks_parameters() {
 526          return new external_function_parameters(
 527              array(
 528                  'scoid' => new external_value(PARAM_INT, 'sco id'),
 529                  'userid' => new external_value(PARAM_INT, 'user id'),
 530                  'attempt' => new external_value(PARAM_INT, 'attempt number (0 for last attempt)', VALUE_DEFAULT, 0)
 531              )
 532          );
 533      }
 534  
 535      /**
 536       * Retrieves SCO tracking data for the given user id and attempt number
 537       *
 538       * @param int $scoid the sco id
 539       * @param int $userid the user id
 540       * @param int $attempt the attempt number
 541       * @return array warnings and the scoes data
 542       * @since Moodle 3.0
 543       */
 544      public static function get_scorm_sco_tracks($scoid, $userid, $attempt = 0) {
 545          global $USER, $DB;
 546  
 547          $params = self::validate_parameters(self::get_scorm_sco_tracks_parameters(),
 548                                              array('scoid' => $scoid, 'userid' => $userid, 'attempt' => $attempt));
 549  
 550          $tracks = array();
 551          $warnings = array();
 552  
 553          $sco = scorm_get_sco($params['scoid'], SCO_ONLY);
 554          if (!$sco) {
 555              throw new moodle_exception('cannotfindsco', 'scorm');
 556          }
 557  
 558          $scorm = $DB->get_record('scorm', array('id' => $sco->scorm), '*', MUST_EXIST);
 559          $cm = get_coursemodule_from_instance('scorm', $scorm->id);
 560  
 561          $context = context_module::instance($cm->id);
 562          self::validate_context($context);
 563  
 564          $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
 565          core_user::require_active_user($user);
 566  
 567          // Extra checks so only users with permissions can view other users attempts.
 568          if ($USER->id != $user->id) {
 569              require_capability('mod/scorm:viewreport', $context);
 570          }
 571  
 572          scorm_require_available($scorm, true, $context);
 573  
 574          if (empty($params['attempt'])) {
 575              $params['attempt'] = scorm_get_last_attempt($scorm->id, $user->id);
 576          }
 577  
 578          $attempted = false;
 579          if ($scormtracks = scorm_get_tracks($sco->id, $params['userid'], $params['attempt'])) {
 580              // Check if attempted.
 581              if ($scormtracks->status != '') {
 582                  $attempted = true;
 583                  foreach ($scormtracks as $element => $value) {
 584                      $tracks[] = array(
 585                          'element' => $element,
 586                          'value' => $value,
 587                      );
 588                  }
 589              }
 590          }
 591  
 592          if (!$attempted) {
 593              $warnings[] = array(
 594                  'item' => 'attempt',
 595                  'itemid' => $params['attempt'],
 596                  'warningcode' => 'notattempted',
 597                  'message' => get_string('notattempted', 'scorm')
 598              );
 599          }
 600  
 601          $result = array();
 602          $result['data']['attempt'] = $params['attempt'];
 603          $result['data']['tracks'] = $tracks;
 604          $result['warnings'] = $warnings;
 605          return $result;
 606      }
 607  
 608      /**
 609       * Describes the get_scorm_sco_tracks return value.
 610       *
 611       * @return external_single_structure
 612       * @since Moodle 3.0
 613       */
 614      public static function get_scorm_sco_tracks_returns() {
 615  
 616          return new external_single_structure(
 617              array(
 618                  'data' => new external_single_structure(
 619                      array(
 620                          'attempt' => new external_value(PARAM_INT, 'Attempt number'),
 621                          'tracks' => new external_multiple_structure(
 622                              new external_single_structure(
 623                                  array(
 624                                      'element' => new external_value(PARAM_RAW, 'Element name'),
 625                                      'value' => new external_value(PARAM_RAW, 'Element value')
 626                                  ), 'Tracks data'
 627                              )
 628                          ),
 629                      ), 'SCO data'
 630                  ),
 631                  'warnings' => new external_warnings(),
 632              )
 633          );
 634      }
 635  
 636      /**
 637       * Describes the parameters for get_scorms_by_courses.
 638       *
 639       * @return external_function_parameters
 640       * @since Moodle 3.0
 641       */
 642      public static function get_scorms_by_courses_parameters() {
 643          return new external_function_parameters (
 644              array(
 645                  'courseids' => new external_multiple_structure(
 646                      new external_value(PARAM_INT, 'course id'), 'Array of course ids', VALUE_DEFAULT, array()
 647                  ),
 648              )
 649          );
 650      }
 651  
 652      /**
 653       * Returns a list of scorms in a provided list of courses,
 654       * if no list is provided all scorms that the user can view will be returned.
 655       *
 656       * @param array $courseids the course ids
 657       * @return array the scorm details
 658       * @since Moodle 3.0
 659       */
 660      public static function get_scorms_by_courses($courseids = array()) {
 661          global $CFG;
 662  
 663          $returnedscorms = array();
 664          $warnings = array();
 665  
 666          $params = self::validate_parameters(self::get_scorms_by_courses_parameters(), array('courseids' => $courseids));
 667  
 668          $courses = array();
 669          if (empty($params['courseids'])) {
 670              $courses = enrol_get_my_courses();
 671              $params['courseids'] = array_keys($courses);
 672          }
 673  
 674          // Ensure there are courseids to loop through.
 675          if (!empty($params['courseids'])) {
 676  
 677              list($courses, $warnings) = external_util::validate_courses($params['courseids'], $courses);
 678  
 679              // Get the scorms in this course, this function checks users visibility permissions.
 680              // We can avoid then additional validate_context calls.
 681              $scorms = get_all_instances_in_courses("scorm", $courses);
 682  
 683              $fs = get_file_storage();
 684              foreach ($scorms as $scorm) {
 685  
 686                  $context = context_module::instance($scorm->coursemodule);
 687  
 688                  // Entry to return.
 689                  $module = helper_for_get_mods_by_courses::standard_coursemodule_element_values($scorm, 'mod_scorm');
 690  
 691                  // Check if the SCORM open and return warnings if so.
 692                  list($open, $openwarnings) = scorm_get_availability_status($scorm, true, $context);
 693  
 694                  if (!$open) {
 695                      foreach ($openwarnings as $warningkey => $warningdata) {
 696                          $warnings[] = array(
 697                              'item' => 'scorm',
 698                              'itemid' => $scorm->id,
 699                              'warningcode' => $warningkey,
 700                              'message' => get_string($warningkey, 'scorm', $warningdata)
 701                          );
 702                      }
 703                  } else {
 704                      $module['packagesize'] = 0;
 705                      // SCORM size.
 706                      if ($scorm->scormtype === SCORM_TYPE_LOCAL or $scorm->scormtype === SCORM_TYPE_LOCALSYNC) {
 707                          if ($packagefile = $fs->get_file($context->id, 'mod_scorm', 'package', 0, '/', $scorm->reference)) {
 708                              $module['packagesize'] = $packagefile->get_filesize();
 709                              // Download URL.
 710                              $module['packageurl'] = moodle_url::make_webservice_pluginfile_url(
 711                                                      $context->id, 'mod_scorm', 'package', 0, '/', $scorm->reference)->out(false);
 712                          }
 713                      }
 714  
 715                      $module['protectpackagedownloads'] = get_config('scorm', 'protectpackagedownloads');
 716  
 717                      $viewablefields = array('version', 'maxgrade', 'grademethod', 'whatgrade', 'maxattempt', 'forcecompleted',
 718                                              'forcenewattempt', 'lastattemptlock', 'displayattemptstatus', 'displaycoursestructure',
 719                                              'sha1hash', 'md5hash', 'revision', 'launch', 'skipview', 'hidebrowse', 'hidetoc', 'nav',
 720                                              'navpositionleft', 'navpositiontop', 'auto', 'popup', 'width', 'height', 'timeopen',
 721                                              'timeclose', 'scormtype', 'reference');
 722  
 723                      // Check additional permissions for returning optional private settings.
 724                      if (has_capability('moodle/course:manageactivities', $context)) {
 725                          $additionalfields = array('updatefreq', 'options', 'completionstatusrequired', 'completionscorerequired',
 726                                                    'completionstatusallscos', 'autocommit', 'timemodified');
 727                          $viewablefields = array_merge($viewablefields, $additionalfields);
 728                      }
 729  
 730                      foreach ($viewablefields as $field) {
 731                          $module[$field] = $scorm->{$field};
 732                      }
 733                  }
 734  
 735                  $returnedscorms[] = $module;
 736              }
 737          }
 738  
 739          $result = array();
 740          $result['scorms'] = $returnedscorms;
 741          $result['warnings'] = $warnings;
 742          return $result;
 743      }
 744  
 745      /**
 746       * Describes the get_scorms_by_courses return value.
 747       *
 748       * @return external_single_structure
 749       * @since Moodle 3.0
 750       */
 751      public static function get_scorms_by_courses_returns() {
 752  
 753          return new external_single_structure(
 754              array(
 755                  'scorms' => new external_multiple_structure(
 756                      new external_single_structure(array_merge(
 757                          helper_for_get_mods_by_courses::standard_coursemodule_elements_returns(),
 758                          [
 759                              'packagesize' => new external_value(PARAM_INT, 'SCORM zip package size', VALUE_OPTIONAL),
 760                              'packageurl' => new external_value(PARAM_URL, 'SCORM zip package URL', VALUE_OPTIONAL),
 761                              'version' => new external_value(PARAM_NOTAGS, 'SCORM version (SCORM_12, SCORM_13, SCORM_AICC)',
 762                                                              VALUE_OPTIONAL),
 763                              'maxgrade' => new external_value(PARAM_INT, 'Max grade', VALUE_OPTIONAL),
 764                              'grademethod' => new external_value(PARAM_INT, 'Grade method', VALUE_OPTIONAL),
 765                              'whatgrade' => new external_value(PARAM_INT, 'What grade', VALUE_OPTIONAL),
 766                              'maxattempt' => new external_value(PARAM_INT, 'Maximum number of attemtps', VALUE_OPTIONAL),
 767                              'forcecompleted' => new external_value(PARAM_BOOL, 'Status current attempt is forced to "completed"',
 768                                                                      VALUE_OPTIONAL),
 769                              'forcenewattempt' => new external_value(PARAM_INT, 'Controls re-entry behaviour',
 770                                                                      VALUE_OPTIONAL),
 771                              'lastattemptlock' => new external_value(PARAM_BOOL, 'Prevents to launch new attempts once finished',
 772                                                                      VALUE_OPTIONAL),
 773                              'displayattemptstatus' => new external_value(PARAM_INT, 'How to display attempt status',
 774                                                                              VALUE_OPTIONAL),
 775                              'displaycoursestructure' => new external_value(PARAM_BOOL, 'Display contents structure',
 776                                                                              VALUE_OPTIONAL),
 777                              'sha1hash' => new external_value(PARAM_NOTAGS, 'Package content or ext path hash', VALUE_OPTIONAL),
 778                              'md5hash' => new external_value(PARAM_NOTAGS, 'MD5 Hash of package file', VALUE_OPTIONAL),
 779                              'revision' => new external_value(PARAM_INT, 'Revison number', VALUE_OPTIONAL),
 780                              'launch' => new external_value(PARAM_INT, 'First content to launch', VALUE_OPTIONAL),
 781                              'skipview' => new external_value(PARAM_INT, 'How to skip the content structure page', VALUE_OPTIONAL),
 782                              'hidebrowse' => new external_value(PARAM_BOOL, 'Disable preview mode?', VALUE_OPTIONAL),
 783                              'hidetoc' => new external_value(PARAM_INT, 'How to display the SCORM structure in player',
 784                                                              VALUE_OPTIONAL),
 785                              'nav' => new external_value(PARAM_INT, 'Show navigation buttons', VALUE_OPTIONAL),
 786                              'navpositionleft' => new external_value(PARAM_INT, 'Navigation position left', VALUE_OPTIONAL),
 787                              'navpositiontop' => new external_value(PARAM_INT, 'Navigation position top', VALUE_OPTIONAL),
 788                              'auto' => new external_value(PARAM_BOOL, 'Auto continue?', VALUE_OPTIONAL),
 789                              'popup' => new external_value(PARAM_INT, 'Display in current or new window', VALUE_OPTIONAL),
 790                              'width' => new external_value(PARAM_INT, 'Frame width', VALUE_OPTIONAL),
 791                              'height' => new external_value(PARAM_INT, 'Frame height', VALUE_OPTIONAL),
 792                              'timeopen' => new external_value(PARAM_INT, 'Available from', VALUE_OPTIONAL),
 793                              'timeclose' => new external_value(PARAM_INT, 'Available to', VALUE_OPTIONAL),
 794                              'scormtype' => new external_value(PARAM_ALPHA, 'SCORM type', VALUE_OPTIONAL),
 795                              'reference' => new external_value(PARAM_NOTAGS, 'Reference to the package', VALUE_OPTIONAL),
 796                              'protectpackagedownloads' => new external_value(PARAM_BOOL, 'Protect package downloads?',
 797                                                                              VALUE_OPTIONAL),
 798                              'updatefreq' => new external_value(PARAM_INT, 'Auto-update frequency for remote packages',
 799                                                                  VALUE_OPTIONAL),
 800                              'options' => new external_value(PARAM_RAW, 'Additional options', VALUE_OPTIONAL),
 801                              'completionstatusrequired' => new external_value(PARAM_INT, 'Status passed/completed required?',
 802                                                                                  VALUE_OPTIONAL),
 803                              'completionscorerequired' => new external_value(PARAM_INT, 'Minimum score required', VALUE_OPTIONAL),
 804                              'completionstatusallscos' => new external_value(PARAM_INT, 'Require all scos to return completion status', VALUE_OPTIONAL),
 805                              'autocommit' => new external_value(PARAM_BOOL, 'Save track data automatically?', VALUE_OPTIONAL),
 806                              'timemodified' => new external_value(PARAM_INT, 'Time of last modification', VALUE_OPTIONAL),
 807                          ]
 808                      ), 'SCORM')
 809                  ),
 810                  'warnings' => new external_warnings(),
 811              )
 812          );
 813      }
 814  
 815      /**
 816       * Returns description of method parameters
 817       *
 818       * @return external_function_parameters
 819       * @since Moodle 3.1
 820       */
 821      public static function launch_sco_parameters() {
 822          return new external_function_parameters(
 823              array(
 824                  'scormid' => new external_value(PARAM_INT, 'SCORM instance id'),
 825                  'scoid' => new external_value(PARAM_INT, 'SCO id (empty for launching the first SCO)', VALUE_DEFAULT, 0)
 826              )
 827          );
 828      }
 829  
 830      /**
 831       * Trigger the course module viewed event.
 832       *
 833       * @param int $scormid the SCORM instance id
 834       * @param int $scoid the SCO id
 835       * @return array of warnings and status result
 836       * @since Moodle 3.1
 837       * @throws moodle_exception
 838       */
 839      public static function launch_sco($scormid, $scoid = 0) {
 840          global $DB, $CFG;
 841  
 842          require_once($CFG->libdir . '/completionlib.php');
 843  
 844          $params = self::validate_parameters(self::launch_sco_parameters(),
 845                                              array(
 846                                                  'scormid' => $scormid,
 847                                                  'scoid' => $scoid
 848                                              ));
 849          $warnings = array();
 850  
 851          // Request and permission validation.
 852          $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
 853          list($course, $cm) = get_course_and_cm_from_instance($scorm, 'scorm');
 854  
 855          $context = context_module::instance($cm->id);
 856          self::validate_context($context);
 857  
 858          // If the SCORM is not open this function will throw exceptions.
 859          scorm_require_available($scorm);
 860  
 861          if (!empty($params['scoid']) and !($sco = scorm_get_sco($params['scoid'], SCO_ONLY))) {
 862              throw new moodle_exception('cannotfindsco', 'scorm');
 863          }
 864  
 865          // Mark module viewed.
 866          $completion = new completion_info($course);
 867          $completion->set_module_viewed($cm);
 868  
 869          list($sco, $scolaunchurl) = scorm_get_sco_and_launch_url($scorm, $params['scoid'], $context);
 870          // Trigger the SCO launched event.
 871          scorm_launch_sco($scorm, $sco, $cm, $context, $scolaunchurl);
 872  
 873          $result = array();
 874          $result['status'] = true;
 875          $result['warnings'] = $warnings;
 876          return $result;
 877      }
 878  
 879      /**
 880       * Returns description of method result value
 881       *
 882       * @return external_description
 883       * @since Moodle 3.1
 884       */
 885      public static function launch_sco_returns() {
 886          return new external_single_structure(
 887              array(
 888                  'status' => new external_value(PARAM_BOOL, 'status: true if success'),
 889                  'warnings' => new external_warnings()
 890              )
 891          );
 892      }
 893  
 894      /**
 895       * Describes the parameters for get_scorm_access_information.
 896       *
 897       * @return external_external_function_parameters
 898       * @since Moodle 3.7
 899       */
 900      public static function get_scorm_access_information_parameters() {
 901          return new external_function_parameters (
 902              array(
 903                  'scormid' => new external_value(PARAM_INT, 'scorm instance id.')
 904              )
 905          );
 906      }
 907  
 908      /**
 909       * Return access information for a given scorm.
 910       *
 911       * @param int $scormid scorm instance id
 912       * @return array of warnings and the access information
 913       * @since Moodle 3.7
 914       * @throws  moodle_exception
 915       */
 916      public static function get_scorm_access_information($scormid) {
 917          global $DB;
 918  
 919          $params = self::validate_parameters(self::get_scorm_access_information_parameters(), array('scormid' => $scormid));
 920  
 921          // Request and permission validation.
 922          $scorm = $DB->get_record('scorm', array('id' => $params['scormid']), '*', MUST_EXIST);
 923          list($course, $cm) = get_course_and_cm_from_instance($scorm, 'scorm');
 924  
 925          $context = context_module::instance($cm->id);
 926          self::validate_context($context);
 927  
 928          $result = array();
 929          // Return all the available capabilities.
 930          $capabilities = load_capability_def('mod_scorm');
 931          foreach ($capabilities as $capname => $capdata) {
 932              // Get fields like cansubmit so it is consistent with the access_information function implemented in other modules.
 933              $field = 'can' . str_replace('mod/scorm:', '', $capname);
 934              $result[$field] = has_capability($capname, $context);
 935          }
 936  
 937          $result['warnings'] = array();
 938          return $result;
 939      }
 940  
 941      /**
 942       * Describes the get_scorm_access_information return value.
 943       *
 944       * @return external_single_structure
 945       * @since Moodle 3.7
 946       */
 947      public static function get_scorm_access_information_returns() {
 948  
 949          $structure = array(
 950              'warnings' => new external_warnings()
 951          );
 952  
 953          $capabilities = load_capability_def('mod_scorm');
 954          foreach ($capabilities as $capname => $capdata) {
 955              // Get fields like cansubmit so it is consistent with the access_information function implemented in other modules.
 956              $field = 'can' . str_replace('mod/scorm:', '', $capname);
 957              $structure[$field] = new external_value(PARAM_BOOL, 'Whether the user has the capability ' . $capname . ' allowed.',
 958                  VALUE_OPTIONAL);
 959          }
 960  
 961          return new external_single_structure($structure);
 962      }
 963  }