Search moodle.org's
Developer Documentation

See Release Notes

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

Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]

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