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 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  /**
  19   * external API for core library
  20   *
  21   * @package    core_webservice
  22   * @category   external
  23   * @copyright  2012 Jerome Mouneyrac <jerome@moodle.com>
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  
  27  defined('MOODLE_INTERNAL') || die;
  28  
  29  require_once("$CFG->libdir/externallib.php");
  30  
  31  /**
  32   * Web service related functions
  33   *
  34   * @package    core
  35   * @category   external
  36   * @copyright  2012 Jerome Mouneyrac <jerome@moodle.com>
  37   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   * @since Moodle 2.4
  39   */
  40  class core_external extends external_api {
  41  
  42  
  43      /**
  44       * Format the received string parameters to be sent to the core get_string() function.
  45       *
  46       * @param array $stringparams
  47       * @return object|string
  48       * @since Moodle 2.4
  49       */
  50      public static function format_string_parameters($stringparams) {
  51          // Check if there are some string params.
  52          $strparams = new stdClass();
  53          if (!empty($stringparams)) {
  54              // There is only one string parameter.
  55              if (count($stringparams) == 1) {
  56                  $stringparam = array_pop($stringparams);
  57                  if (isset($stringparam['name'])) {
  58                      $strparams->{$stringparam['name']} = $stringparam['value'];
  59                  } else {
  60                      // It is a not named string parameter.
  61                      $strparams = $stringparam['value'];
  62                  }
  63              }  else {
  64                  // There are more than one parameter.
  65                  foreach ($stringparams as $stringparam) {
  66  
  67                      // If a parameter is unnamed throw an exception
  68                      // unnamed param is only possible if one only param is sent.
  69                      if (empty($stringparam['name'])) {
  70                          throw new moodle_exception('unnamedstringparam', 'webservice');
  71                      }
  72  
  73                      $strparams->{$stringparam['name']} = $stringparam['value'];
  74                  }
  75              }
  76          }
  77          return $strparams;
  78      }
  79  
  80      /**
  81       * Returns description of get_string parameters
  82       *
  83       * @return external_function_parameters
  84       * @since Moodle 2.4
  85       */
  86      public static function get_string_parameters() {
  87          return new external_function_parameters(
  88              array('stringid' => new external_value(PARAM_STRINGID, 'string identifier'),
  89                    'component' => new external_value(PARAM_COMPONENT,'component', VALUE_DEFAULT, 'moodle'),
  90                    'lang' => new external_value(PARAM_LANG, 'lang', VALUE_DEFAULT, null),
  91                    'stringparams' => new external_multiple_structure (
  92                        new external_single_structure(array(
  93                            'name' => new external_value(PARAM_ALPHANUMEXT, 'param name
  94                              - if the string expect only one $a parameter then don\'t send this field, just send the value.', VALUE_OPTIONAL),
  95                            'value' => new external_value(PARAM_RAW,'param value'))),
  96                            'the definition of a string param (i.e. {$a->name})', VALUE_DEFAULT, array()
  97                     )
  98              )
  99          );
 100      }
 101  
 102      /**
 103       * Return a core get_string() call
 104       *
 105       * @param string $identifier string identifier
 106       * @param string $component string component
 107       * @param array $stringparams the string params
 108       * @return string
 109       * @since Moodle 2.4
 110       */
 111      public static function get_string($stringid, $component = 'moodle', $lang = null, $stringparams = array()) {
 112          $params = self::validate_parameters(self::get_string_parameters(),
 113                        array('stringid'=>$stringid, 'component' => $component, 'lang' => $lang, 'stringparams' => $stringparams));
 114  
 115          $stringmanager = get_string_manager();
 116          return $stringmanager->get_string($params['stringid'], $params['component'],
 117              core_external::format_string_parameters($params['stringparams']), $params['lang']);
 118      }
 119  
 120      /**
 121       * Returns description of get_string() result value
 122       *
 123       * @return external_description
 124       * @since Moodle 2.4
 125       */
 126      public static function get_string_returns() {
 127          return new external_value(PARAM_RAW, 'translated string');
 128      }
 129  
 130      /**
 131       * Returns description of get_string parameters
 132       *
 133       * @return external_function_parameters
 134       * @since Moodle 2.4
 135       */
 136      public static function get_strings_parameters() {
 137          return new external_function_parameters(
 138              array('strings' => new external_multiple_structure (
 139                      new external_single_structure (array(
 140                          'stringid' => new external_value(PARAM_STRINGID, 'string identifier'),
 141                          'component' => new external_value(PARAM_COMPONENT, 'component', VALUE_DEFAULT, 'moodle'),
 142                          'lang' => new external_value(PARAM_LANG, 'lang', VALUE_DEFAULT, null),
 143                          'stringparams' => new external_multiple_structure (
 144                              new external_single_structure(array(
 145                                  'name' => new external_value(PARAM_ALPHANUMEXT, 'param name
 146                                      - if the string expect only one $a parameter then don\'t send this field, just send the value.', VALUE_OPTIONAL),
 147                                  'value' => new external_value(PARAM_RAW, 'param value'))),
 148                                  'the definition of a string param (i.e. {$a->name})', VALUE_DEFAULT, array()
 149                          ))
 150                      )
 151                  )
 152              )
 153          );
 154      }
 155  
 156      /**
 157       * Return multiple call to core get_string()
 158       *
 159       * @param array $strings strings to translate
 160       * @return array
 161       *
 162       * @since Moodle 2.4
 163       */
 164      public static function get_strings($strings) {
 165          $params = self::validate_parameters(self::get_strings_parameters(),
 166                        array('strings'=>$strings));
 167          $stringmanager = get_string_manager();
 168  
 169          $translatedstrings = array();
 170          foreach($params['strings'] as $string) {
 171  
 172              if (!empty($string['lang'])) {
 173                  $lang = $string['lang'];
 174              } else {
 175                  $lang = current_language();
 176              }
 177  
 178              $translatedstrings[] = array(
 179                  'stringid' => $string['stringid'],
 180                  'component' => $string['component'],
 181                  'lang' => $lang,
 182                  'string' => $stringmanager->get_string($string['stringid'], $string['component'],
 183                      core_external::format_string_parameters($string['stringparams']), $lang));
 184          }
 185  
 186          return $translatedstrings;
 187      }
 188  
 189      /**
 190       * Returns description of get_string() result value
 191       *
 192       * @return external_description
 193       * @since Moodle 2.4
 194       */
 195      public static function get_strings_returns() {
 196          return new external_multiple_structure(
 197              new external_single_structure(array(
 198                  'stringid' => new external_value(PARAM_STRINGID, 'string id'),
 199                  'component' => new external_value(PARAM_COMPONENT, 'string component'),
 200                  'lang' => new external_value(PARAM_LANG, 'lang'),
 201                  'string' => new external_value(PARAM_RAW, 'translated string'))
 202              ));
 203      }
 204  
 205      /**
 206       * Returns description of get_user_dates parameters
 207       *
 208       * @return external_function_parameters
 209       */
 210      public static function get_user_dates_parameters() {
 211          return new external_function_parameters(
 212              [
 213                  'contextid' => new external_value(
 214                      PARAM_INT,
 215                      'Context ID. Either use this value, or level and instanceid.',
 216                      VALUE_DEFAULT,
 217                      0
 218                  ),
 219                  'contextlevel' => new external_value(
 220                      PARAM_ALPHA,
 221                      'Context level. To be used with instanceid.',
 222                      VALUE_DEFAULT,
 223                      ''
 224                  ),
 225                  'instanceid' => new external_value(
 226                      PARAM_INT,
 227                      'Context instance ID. To be used with level',
 228                      VALUE_DEFAULT,
 229                      0
 230                  ),
 231                  'timestamps' => new external_multiple_structure (
 232                      new external_single_structure (
 233                          [
 234                              'timestamp' => new external_value(PARAM_INT, 'unix timestamp'),
 235                              'format' => new external_value(PARAM_TEXT, 'format string'),
 236                              'type' => new external_value(PARAM_PLUGIN, 'The calendar type', VALUE_DEFAULT),
 237                              'fixday' => new external_value(PARAM_INT, 'Remove leading zero for day', VALUE_DEFAULT, 1),
 238                              'fixhour' => new external_value(PARAM_INT, 'Remove leading zero for hour', VALUE_DEFAULT, 1),
 239                          ]
 240                      )
 241                  )
 242              ]
 243          );
 244      }
 245  
 246      /**
 247       * Format an array of timestamps.
 248       *
 249       * @param int|null $contextid The contenxt id
 250       * @param string|null $contextlevel The context level
 251       * @param int|null $instanceid The instnace id for the context level
 252       * @param array $timestamps Timestamps to format
 253       * @return array
 254       */
 255      public static function get_user_dates($contextid, $contextlevel, $instanceid, $timestamps) {
 256          $params = self::validate_parameters(
 257              self::get_user_dates_parameters(),
 258              [
 259                  'contextid' => $contextid,
 260                  'contextlevel' => $contextlevel,
 261                  'instanceid' => $instanceid,
 262                  'timestamps' => $timestamps,
 263              ]
 264          );
 265  
 266          $context = self::get_context_from_params($params);
 267          self::validate_context($context);
 268  
 269          $formatteddates = array_map(function($timestamp) {
 270  
 271              $calendartype = $timestamp['type'];
 272              $fixday = !empty($timestamp['fixday']);
 273              $fixhour = !empty($timestamp['fixhour']);
 274              $calendar  = \core_calendar\type_factory::get_calendar_instance($calendartype);
 275              return $calendar->timestamp_to_date_string($timestamp['timestamp'], $timestamp['format'], 99, $fixday, $fixhour);
 276          }, $params['timestamps']);
 277  
 278          return ['dates' => $formatteddates];
 279      }
 280  
 281      /**
 282       * Returns description of get_user_dates() result value
 283       *
 284       * @return external_description
 285       */
 286      public static function get_user_dates_returns() {
 287          return new external_single_structure(
 288              [
 289                  'dates' => new external_multiple_structure (
 290                      new external_value(PARAM_TEXT, 'formatted dates strings')
 291                  )
 292              ]
 293          );
 294      }
 295  
 296       /**
 297       * Returns description of get_component_strings parameters
 298       *
 299       * @return external_function_parameters
 300       * @since Moodle 2.4
 301       */
 302      public static function get_component_strings_parameters() {
 303          return new external_function_parameters(
 304              array('component' => new external_value(PARAM_COMPONENT, 'component'),
 305                    'lang' => new external_value(PARAM_LANG, 'lang', VALUE_DEFAULT, null),
 306              )
 307          );
 308      }
 309  
 310      /**
 311       * Return all lang strings of a component - call to core get_component_strings().
 312       *
 313       * @param string $component component name
 314       * @return array
 315       *
 316       * @since Moodle 2.4
 317       */
 318      public static function get_component_strings($component, $lang = null) {
 319  
 320          if (empty($lang)) {
 321              $lang = current_language();
 322          }
 323  
 324          $params = self::validate_parameters(self::get_component_strings_parameters(),
 325                        array('component'=>$component, 'lang' => $lang));
 326  
 327          $stringmanager = get_string_manager();
 328  
 329          $wsstrings = array();
 330          $componentstrings = $stringmanager->load_component_strings($params['component'], $params['lang']);
 331          foreach($componentstrings as $stringid => $string) {
 332              $wsstring = array();
 333              $wsstring['stringid'] = $stringid;
 334              $wsstring['string'] = $string;
 335              $wsstrings[] = $wsstring;
 336          }
 337  
 338          return $wsstrings;
 339      }
 340  
 341      /**
 342       * Returns description of get_component_strings() result value
 343       *
 344       * @return external_description
 345       * @since Moodle 2.4
 346       */
 347      public static function get_component_strings_returns() {
 348          return new external_multiple_structure(
 349              new external_single_structure(array(
 350                  'stringid' => new external_value(PARAM_STRINGID, 'string id'),
 351                  'string' => new external_value(PARAM_RAW, 'translated string'))
 352              ));
 353      }
 354  
 355      /**
 356       * Returns description of get_fragment parameters
 357       *
 358       * @return external_function_parameters
 359       * @since Moodle 3.1
 360       */
 361      public static function get_fragment_parameters() {
 362          return new external_function_parameters(
 363              array(
 364                  'component' => new external_value(PARAM_COMPONENT, 'Component for the callback e.g. mod_assign'),
 365                  'callback' => new external_value(PARAM_ALPHANUMEXT, 'Name of the callback to execute'),
 366                  'contextid' => new external_value(PARAM_INT, 'Context ID that the fragment is from'),
 367                  'args' => new external_multiple_structure(
 368                      new external_single_structure(
 369                          array(
 370                              'name' => new external_value(PARAM_ALPHANUMEXT, 'param name'),
 371                              'value' => new external_value(PARAM_RAW, 'param value')
 372                          )
 373                      ), 'args for the callback are optional', VALUE_OPTIONAL
 374                  )
 375              )
 376          );
 377      }
 378  
 379      /**
 380       * Get a HTML fragment for inserting into something. Initial use is for inserting mforms into
 381       * a page using AJAX.
 382       * This web service is designed to be called only via AJAX and not directly.
 383       * Callbacks that are called by this web service are responsible for doing the appropriate security checks
 384       * to access the information returned. This only does minimal validation on the context.
 385       *
 386       * @param string $component Name of the component.
 387       * @param string $callback Function callback name.
 388       * @param int $contextid Context ID this fragment is in.
 389       * @param array $args optional arguments for the callback.
 390       * @return array HTML and JavaScript fragments for insertion into stuff.
 391       * @since Moodle 3.1
 392       */
 393      public static function get_fragment($component, $callback, $contextid, $args = null) {
 394          global $OUTPUT, $PAGE;
 395  
 396          $params = self::validate_parameters(self::get_fragment_parameters(),
 397                  array(
 398                      'component' => $component,
 399                      'callback' => $callback,
 400                      'contextid' => $contextid,
 401                      'args' => $args
 402                  )
 403          );
 404  
 405          // Reformat arguments into something less unwieldy.
 406          $arguments = array();
 407          foreach ($params['args'] as $paramargument) {
 408              $arguments[$paramargument['name']] = $paramargument['value'];
 409          }
 410  
 411          $context = context::instance_by_id($contextid);
 412          self::validate_context($context);
 413          $arguments['context'] = $context;
 414  
 415          // Hack alert: Set a default URL to stop the annoying debug.
 416          $PAGE->set_url('/');
 417          // Hack alert: Forcing bootstrap_renderer to initiate moodle page.
 418          $OUTPUT->header();
 419  
 420          // Overwriting page_requirements_manager with the fragment one so only JS included from
 421          // this point is returned to the user.
 422          $PAGE->start_collecting_javascript_requirements();
 423          $data = component_callback($params['component'], 'output_fragment_' . $params['callback'], array($arguments));
 424          $jsfooter = $PAGE->requires->get_end_code();
 425          $output = array('html' => $data, 'javascript' => $jsfooter);
 426          return $output;
 427      }
 428  
 429      /**
 430       * Returns description of get_fragment() result value
 431       *
 432       * @return external_description
 433       * @since Moodle 3.1
 434       */
 435      public static function get_fragment_returns() {
 436          return new external_single_structure(
 437              array(
 438                  'html' => new external_value(PARAM_RAW, 'HTML fragment.'),
 439                  'javascript' => new external_value(PARAM_RAW, 'JavaScript fragment')
 440              )
 441          );
 442      }
 443  
 444      /**
 445       * Parameters for function update_inplace_editable()
 446       *
 447       * @since Moodle 3.1
 448       * @return external_function_parameters
 449       */
 450      public static function update_inplace_editable_parameters() {
 451          return new external_function_parameters(
 452              array(
 453                  'component' => new external_value(PARAM_COMPONENT, 'component responsible for the update', VALUE_REQUIRED),
 454                  'itemtype' => new external_value(PARAM_NOTAGS, 'type of the updated item inside the component', VALUE_REQUIRED),
 455                  'itemid' => new external_value(PARAM_RAW, 'identifier of the updated item', VALUE_REQUIRED),
 456                  'value' => new external_value(PARAM_RAW, 'new value', VALUE_REQUIRED),
 457              ));
 458      }
 459  
 460      /**
 461       * Update any component's editable value assuming that component implements necessary callback
 462       *
 463       * @since Moodle 3.1
 464       * @param string $component
 465       * @param string $itemtype
 466       * @param string $itemid
 467       * @param string $value
 468       */
 469      public static function update_inplace_editable($component, $itemtype, $itemid, $value) {
 470          global $PAGE;
 471          // Validate and normalize parameters.
 472          $params = self::validate_parameters(self::update_inplace_editable_parameters(),
 473                        array('component' => $component, 'itemtype' => $itemtype, 'itemid' => $itemid, 'value' => $value));
 474          if (!$functionname = component_callback_exists($component, 'inplace_editable')) {
 475              throw new \moodle_exception('inplaceeditableerror');
 476          }
 477          $tmpl = component_callback($params['component'], 'inplace_editable',
 478              array($params['itemtype'], $params['itemid'], $params['value']));
 479          if (!$tmpl || !($tmpl instanceof \core\output\inplace_editable)) {
 480              throw new \moodle_exception('inplaceeditableerror');
 481          }
 482          return $tmpl->export_for_template($PAGE->get_renderer('core'));
 483      }
 484  
 485      /**
 486       * Return structure for update_inplace_editable()
 487       *
 488       * @since Moodle 3.1
 489       * @return external_description
 490       */
 491      public static function update_inplace_editable_returns() {
 492          return new external_single_structure(
 493              array(
 494                  'displayvalue' => new external_value(PARAM_RAW, 'display value (may contain link or other html tags)'),
 495                  'component' => new external_value(PARAM_NOTAGS, 'component responsible for the update', VALUE_OPTIONAL),
 496                  'itemtype' => new external_value(PARAM_NOTAGS, 'itemtype', VALUE_OPTIONAL),
 497                  'value' => new external_value(PARAM_RAW, 'value of the item as it is stored', VALUE_OPTIONAL),
 498                  'itemid' => new external_value(PARAM_RAW, 'identifier of the updated item', VALUE_OPTIONAL),
 499                  'edithint' => new external_value(PARAM_NOTAGS, 'hint for editing element', VALUE_OPTIONAL),
 500                  'editlabel' => new external_value(PARAM_RAW, 'label for editing element', VALUE_OPTIONAL),
 501                  'editicon' => new external_single_structure([
 502                      'key' => new external_value(PARAM_RAW, 'Edit icon key', VALUE_OPTIONAL),
 503                      'component' => new external_value(PARAM_COMPONENT, 'Edit icon component', VALUE_OPTIONAL),
 504                      'title' => new external_value(PARAM_NOTAGS, 'Edit icon title', VALUE_OPTIONAL),
 505                  ]),
 506                  'type' => new external_value(PARAM_ALPHA, 'type of the element (text, toggle, select)', VALUE_OPTIONAL),
 507                  'options' => new external_value(PARAM_RAW, 'options of the element, format depends on type', VALUE_OPTIONAL),
 508                  'linkeverything' => new external_value(PARAM_INT, 'Should everything be wrapped in the edit link or link displayed separately', VALUE_OPTIONAL),
 509              )
 510          );
 511      }
 512  
 513      /**
 514       * Returns description of fetch_notifications() parameters.
 515       *
 516       * @return external_function_parameters
 517       * @since Moodle 3.1
 518       */
 519      public static function fetch_notifications_parameters() {
 520          return new external_function_parameters(
 521              array(
 522                  'contextid' => new external_value(PARAM_INT, 'Context ID', VALUE_REQUIRED),
 523              ));
 524      }
 525  
 526      /**
 527       * Returns description of fetch_notifications() result value.
 528       *
 529       * @return external_description
 530       * @since Moodle 3.1
 531       */
 532      public static function fetch_notifications_returns() {
 533          return new external_multiple_structure(
 534              new external_single_structure(
 535                  array(
 536                      'template'      => new external_value(PARAM_RAW, 'Name of the template'),
 537                      'variables'     => new external_single_structure(array(
 538                          'message'       => new external_value(PARAM_RAW, 'HTML content of the Notification'),
 539                          'extraclasses'  => new external_value(PARAM_RAW, 'Extra classes to provide to the tmeplate'),
 540                          'announce'      => new external_value(PARAM_RAW, 'Whether to announce'),
 541                          'closebutton'   => new external_value(PARAM_RAW, 'Whether to close'),
 542                      )),
 543                  )
 544              )
 545          );
 546      }
 547  
 548      /**
 549       * Returns the list of notifications against the current session.
 550       *
 551       * @return array
 552       * @since Moodle 3.1
 553       */
 554      public static function fetch_notifications($contextid) {
 555          global $PAGE;
 556  
 557          self::validate_parameters(self::fetch_notifications_parameters(), [
 558                  'contextid' => $contextid,
 559              ]);
 560  
 561          $context = \context::instance_by_id($contextid);
 562          self::validate_context($context);
 563  
 564          return \core\notification::fetch_as_array($PAGE->get_renderer('core'));
 565      }
 566  }