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   * Glossary module external API.
  19   *
  20   * @package    mod_glossary
  21   * @category   external
  22   * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   * @since      Moodle 3.1
  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/glossary/lib.php');
  33  
  34  /**
  35   * Glossary module external functions.
  36   *
  37   * @package    mod_glossary
  38   * @category   external
  39   * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
  40   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  41   * @since      Moodle 3.1
  42   */
  43  class mod_glossary_external extends external_api {
  44  
  45      /**
  46       * Get the browse modes from the display format.
  47       *
  48       * This returns some of the terms that can be used when reporting a glossary being viewed.
  49       *
  50       * @param  string $format The display format of the glossary.
  51       * @return array Containing some of all of the following: letter, cat, date, author.
  52       */
  53      protected static function get_browse_modes_from_display_format($format) {
  54          global $DB;
  55  
  56          $formats = array();
  57          $dp = $DB->get_record('glossary_formats', array('name' => $format), '*', IGNORE_MISSING);
  58          if ($dp) {
  59              $formats = glossary_get_visible_tabs($dp);
  60          }
  61  
  62          // Always add 'letter'.
  63          $modes = array('letter');
  64  
  65          if (in_array('category', $formats)) {
  66              $modes[] = 'cat';
  67          }
  68          if (in_array('date', $formats)) {
  69              $modes[] = 'date';
  70          }
  71          if (in_array('author', $formats)) {
  72              $modes[] = 'author';
  73          }
  74  
  75          return $modes;
  76      }
  77  
  78      /**
  79       * Get the return value of an entry.
  80       *
  81       * @param bool $includecat Whether the definition should include category info.
  82       * @return external_definition
  83       */
  84      protected static function get_entry_return_structure($includecat = false) {
  85          $params = array(
  86              'id' => new external_value(PARAM_INT, 'The entry ID'),
  87              'glossaryid' => new external_value(PARAM_INT, 'The glossary ID'),
  88              'userid' => new external_value(PARAM_INT, 'Author ID'),
  89              'userfullname' => new external_value(PARAM_NOTAGS, 'Author full name'),
  90              'userpictureurl' => new external_value(PARAM_URL, 'Author picture'),
  91              'concept' => new external_value(PARAM_RAW, 'The concept'),
  92              'definition' => new external_value(PARAM_RAW, 'The definition'),
  93              'definitionformat' => new external_format_value('definition'),
  94              'definitiontrust' => new external_value(PARAM_BOOL, 'The definition trust flag'),
  95              'definitioninlinefiles' => new external_files('entry definition inline files', VALUE_OPTIONAL),
  96              'attachment' => new external_value(PARAM_BOOL, 'Whether or not the entry has attachments'),
  97              'attachments' => new external_files('attachments', VALUE_OPTIONAL),
  98              'timecreated' => new external_value(PARAM_INT, 'Time created'),
  99              'timemodified' => new external_value(PARAM_INT, 'Time modified'),
 100              'teacherentry' => new external_value(PARAM_BOOL, 'The entry was created by a teacher, or equivalent.'),
 101              'sourceglossaryid' => new external_value(PARAM_INT, 'The source glossary ID'),
 102              'usedynalink' => new external_value(PARAM_BOOL, 'Whether the concept should be automatically linked'),
 103              'casesensitive' => new external_value(PARAM_BOOL, 'When true, the matching is case sensitive'),
 104              'fullmatch' => new external_value(PARAM_BOOL, 'When true, the matching is done on full words only'),
 105              'approved' => new external_value(PARAM_BOOL, 'Whether the entry was approved'),
 106              'tags' => new external_multiple_structure(
 107                  \core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
 108              ),
 109          );
 110  
 111          if ($includecat) {
 112              $params['categoryid'] = new external_value(PARAM_INT, 'The category ID. This may be' .
 113                  ' \''. GLOSSARY_SHOW_NOT_CATEGORISED . '\' when the entry is not categorised', VALUE_DEFAULT,
 114                  GLOSSARY_SHOW_NOT_CATEGORISED);
 115              $params['categoryname'] = new external_value(PARAM_RAW, 'The category name. May be empty when the entry is' .
 116                  ' not categorised, or the request was limited to one category.', VALUE_DEFAULT, '');
 117          }
 118  
 119          return new external_single_structure($params);
 120      }
 121  
 122      /**
 123       * Fill in an entry object.
 124       *
 125       * This adds additional required fields for the external function to return.
 126       *
 127       * @param  stdClass $entry   The entry.
 128       * @param  context  $context The context the entry belongs to.
 129       * @return void
 130       */
 131      protected static function fill_entry_details($entry, $context) {
 132          global $PAGE;
 133          $canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
 134  
 135          // Format concept and definition.
 136          $entry->concept = external_format_string($entry->concept, $context->id);
 137          list($entry->definition, $entry->definitionformat) = external_format_text($entry->definition, $entry->definitionformat,
 138              $context->id, 'mod_glossary', 'entry', $entry->id);
 139  
 140          // Author details.
 141          $user = mod_glossary_entry_query_builder::get_user_from_record($entry);
 142          $userpicture = new user_picture($user);
 143          $userpicture->size = 1;
 144          $entry->userfullname = fullname($user, $canviewfullnames);
 145          $entry->userpictureurl = $userpicture->get_url($PAGE)->out(false);
 146  
 147          // Fetch attachments.
 148          $entry->attachment = !empty($entry->attachment) ? 1 : 0;
 149          $entry->attachments = array();
 150          if ($entry->attachment) {
 151              $entry->attachments = external_util::get_area_files($context->id, 'mod_glossary', 'attachment', $entry->id);
 152          }
 153          $definitioninlinefiles = external_util::get_area_files($context->id, 'mod_glossary', 'entry', $entry->id);
 154          if (!empty($definitioninlinefiles)) {
 155              $entry->definitioninlinefiles = $definitioninlinefiles;
 156          }
 157  
 158          $entry->tags = \core_tag\external\util::get_item_tags('mod_glossary', 'glossary_entries', $entry->id);
 159      }
 160  
 161      /**
 162       * Validate a glossary via ID.
 163       *
 164       * @param  int $id The glossary ID.
 165       * @return array Contains glossary, context, course and cm.
 166       */
 167      public static function validate_glossary($id) {
 168          global $DB;
 169          $glossary = $DB->get_record('glossary', array('id' => $id), '*', MUST_EXIST);
 170          list($course, $cm) = get_course_and_cm_from_instance($glossary, 'glossary');
 171          $context = context_module::instance($cm->id);
 172          self::validate_context($context);
 173          return array($glossary, $context, $course, $cm);
 174      }
 175  
 176      /**
 177       * Describes the parameters for get_glossaries_by_courses.
 178       *
 179       * @return external_function_parameters
 180       * @since Moodle 3.1
 181       */
 182      public static function get_glossaries_by_courses_parameters() {
 183          return new external_function_parameters (
 184              array(
 185                  'courseids' => new external_multiple_structure(
 186                      new external_value(PARAM_INT, 'course id'),
 187                      'Array of course IDs', VALUE_DEFAULT, array()
 188                  ),
 189              )
 190          );
 191      }
 192  
 193      /**
 194       * Returns a list of glossaries in a provided list of courses.
 195       *
 196       * If no list is provided all glossaries that the user can view will be returned.
 197       *
 198       * @param array $courseids the course IDs.
 199       * @return array of glossaries
 200       * @since Moodle 3.1
 201       */
 202      public static function get_glossaries_by_courses($courseids = array()) {
 203          global $CFG;
 204          $params = self::validate_parameters(self::get_glossaries_by_courses_parameters(), array('courseids' => $courseids));
 205  
 206          $warnings = array();
 207          $courses = array();
 208          $courseids = $params['courseids'];
 209  
 210          if (empty($courseids)) {
 211              $courses = enrol_get_my_courses();
 212              $courseids = array_keys($courses);
 213          }
 214  
 215          // Array to store the glossaries to return.
 216          $glossaries = array();
 217          $modes = array();
 218  
 219          // Ensure there are courseids to loop through.
 220          if (!empty($courseids)) {
 221              list($courses, $warnings) = external_util::validate_courses($courseids, $courses);
 222  
 223              // Get the glossaries in these courses, this function checks users visibility permissions.
 224              $glossaries = get_all_instances_in_courses('glossary', $courses);
 225              foreach ($glossaries as $glossary) {
 226                  $context = context_module::instance($glossary->coursemodule);
 227                  helper_for_get_mods_by_courses::format_name_and_intro($glossary, 'mod_glossary');
 228  
 229                  // Make sure we have a number of entries per page.
 230                  if (!$glossary->entbypage) {
 231                      $glossary->entbypage = $CFG->glossary_entbypage;
 232                  }
 233  
 234                  // Add the list of browsing modes.
 235                  if (!isset($modes[$glossary->displayformat])) {
 236                      $modes[$glossary->displayformat] = self::get_browse_modes_from_display_format($glossary->displayformat);
 237                  }
 238                  $glossary->browsemodes = $modes[$glossary->displayformat];
 239                  $glossary->canaddentry = has_capability('mod/glossary:write', $context) ? 1 : 0;
 240              }
 241          }
 242  
 243          $result = array();
 244          $result['glossaries'] = $glossaries;
 245          $result['warnings'] = $warnings;
 246          return $result;
 247      }
 248  
 249      /**
 250       * Describes the get_glossaries_by_courses return value.
 251       *
 252       * @return external_single_structure
 253       * @since Moodle 3.1
 254       */
 255      public static function get_glossaries_by_courses_returns() {
 256          return new external_single_structure(array(
 257              'glossaries' => new external_multiple_structure(
 258                  new external_single_structure(array_merge(
 259                      helper_for_get_mods_by_courses::standard_coursemodule_elements_returns(),
 260                      [
 261                      'allowduplicatedentries' => new external_value(PARAM_INT, 'If enabled, multiple entries can have the' .
 262                          ' same concept name'),
 263                      'displayformat' => new external_value(PARAM_TEXT, 'Display format type'),
 264                      'mainglossary' => new external_value(PARAM_INT, 'If enabled this glossary is a main glossary.'),
 265                      'showspecial' => new external_value(PARAM_INT, 'If enabled, participants can browse the glossary by' .
 266                          ' special characters, such as @ and #'),
 267                      'showalphabet' => new external_value(PARAM_INT, 'If enabled, participants can browse the glossary by' .
 268                          ' letters of the alphabet'),
 269                      'showall' => new external_value(PARAM_INT, 'If enabled, participants can browse all entries at once'),
 270                      'allowcomments' => new external_value(PARAM_INT, 'If enabled, all participants with permission to' .
 271                          ' create comments will be able to add comments to glossary entries'),
 272                      'allowprintview' => new external_value(PARAM_INT, 'If enabled, students are provided with a link to a' .
 273                          ' printer-friendly version of the glossary. The link is always available to teachers'),
 274                      'usedynalink' => new external_value(PARAM_INT, 'If site-wide glossary auto-linking has been enabled' .
 275                          ' by an administrator and this checkbox is ticked, the entry will be automatically linked' .
 276                          ' wherever the concept words and phrases appear throughout the rest of the course.'),
 277                      'defaultapproval' => new external_value(PARAM_INT, 'If set to no, entries require approving by a' .
 278                          ' teacher before they are viewable by everyone.'),
 279                      'approvaldisplayformat' => new external_value(PARAM_TEXT, 'When approving glossary items you may wish' .
 280                          ' to use a different display format'),
 281                      'globalglossary' => new external_value(PARAM_INT, ''),
 282                      'entbypage' => new external_value(PARAM_INT, 'Entries shown per page'),
 283                      'editalways' => new external_value(PARAM_INT, 'Always allow editing'),
 284                      'rsstype' => new external_value(PARAM_INT, 'To enable the RSS feed for this activity, select either' .
 285                          ' concepts with author or concepts without author to be included in the feed'),
 286                      'rssarticles' => new external_value(PARAM_INT, 'This setting specifies the number of glossary entry' .
 287                          ' concepts to include in the RSS feed. Between 5 and 20 generally acceptable'),
 288                      'assessed' => new external_value(PARAM_INT, 'Aggregate type'),
 289                      'assesstimestart' => new external_value(PARAM_INT, 'Restrict rating to items created after this'),
 290                      'assesstimefinish' => new external_value(PARAM_INT, 'Restrict rating to items created before this'),
 291                      'scale' => new external_value(PARAM_INT, 'Scale ID'),
 292                      'timecreated' => new external_value(PARAM_INT, 'Time created'),
 293                      'timemodified' => new external_value(PARAM_INT, 'Time modified'),
 294                      'completionentries' => new external_value(PARAM_INT, 'Number of entries to complete'),
 295                      'browsemodes' => new external_multiple_structure(
 296                          new external_value(PARAM_ALPHA, 'Modes of browsing allowed')
 297                      ),
 298                      'canaddentry' => new external_value(PARAM_INT, 'Whether the user can add a new entry', VALUE_OPTIONAL),
 299                      ]
 300                  ), 'Glossaries')
 301              ),
 302              'warnings' => new external_warnings())
 303          );
 304      }
 305  
 306      /**
 307       * Returns the description of the external function parameters.
 308       *
 309       * @return external_function_parameters
 310       * @since Moodle 3.1
 311       */
 312      public static function view_glossary_parameters() {
 313          return new external_function_parameters(array(
 314              'id' => new external_value(PARAM_INT, 'Glossary instance ID'),
 315              'mode' => new external_value(PARAM_ALPHA, 'The mode in which the glossary is viewed'),
 316          ));
 317      }
 318  
 319      /**
 320       * Notify that the course module was viewed.
 321       *
 322       * @param int $id The glossary instance ID.
 323       * @param string $mode The view mode.
 324       * @return array of warnings and status result
 325       * @since Moodle 3.1
 326       * @throws moodle_exception
 327       */
 328      public static function view_glossary($id, $mode) {
 329          $params = self::validate_parameters(self::view_glossary_parameters(), array(
 330              'id' => $id,
 331              'mode' => $mode
 332          ));
 333          $id = $params['id'];
 334          $mode = $params['mode'];
 335          $warnings = array();
 336  
 337          // Get and validate the glossary.
 338          list($glossary, $context, $course, $cm) = self::validate_glossary($id);
 339  
 340          // Trigger module viewed event.
 341          glossary_view($glossary, $course, $cm, $context, $mode);
 342  
 343          return array(
 344              'status' => true,
 345              'warnings' => $warnings
 346          );
 347      }
 348  
 349      /**
 350       * Returns the description of the external function return value.
 351       *
 352       * @return external_description
 353       * @since Moodle 3.1
 354       */
 355      public static function view_glossary_returns() {
 356          return new external_single_structure(array(
 357              'status' => new external_value(PARAM_BOOL, 'True on success'),
 358              'warnings' => new external_warnings()
 359          ));
 360      }
 361  
 362      /**
 363       * Returns the description of the external function parameters.
 364       *
 365       * @return external_function_parameters
 366       * @since Moodle 3.1
 367       */
 368      public static function view_entry_parameters() {
 369          return new external_function_parameters(array(
 370              'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
 371          ));
 372      }
 373  
 374      /**
 375       * Notify that the entry was viewed.
 376       *
 377       * @param int $id The entry ID.
 378       * @return array of warnings and status result
 379       * @since Moodle 3.1
 380       * @throws moodle_exception
 381       * @throws invalid_parameter_exception
 382       */
 383      public static function view_entry($id) {
 384          global $DB, $USER;
 385  
 386          $params = self::validate_parameters(self::view_entry_parameters(), array('id' => $id));
 387          $id = $params['id'];
 388          $warnings = array();
 389  
 390          // Get and validate the glossary.
 391          $entry = $DB->get_record('glossary_entries', array('id' => $id), '*', MUST_EXIST);
 392          list($glossary, $context, $course, $cm) = self::validate_glossary($entry->glossaryid);
 393  
 394          if (!glossary_can_view_entry($entry, $cm)) {
 395              throw new invalid_parameter_exception('invalidentry');
 396          }
 397  
 398          // Trigger view.
 399          glossary_entry_view($entry, $context);
 400  
 401          return array(
 402              'status' => true,
 403              'warnings' => $warnings
 404          );
 405      }
 406  
 407      /**
 408       * Returns the description of the external function return value.
 409       *
 410       * @return external_description
 411       * @since Moodle 3.1
 412       */
 413      public static function view_entry_returns() {
 414          return new external_single_structure(array(
 415              'status' => new external_value(PARAM_BOOL, 'True on success'),
 416              'warnings' => new external_warnings()
 417          ));
 418      }
 419  
 420      /**
 421       * Returns the description of the external function parameters.
 422       *
 423       * @return external_function_parameters
 424       * @since Moodle 3.1
 425       */
 426      public static function get_entries_by_letter_parameters() {
 427          return new external_function_parameters(array(
 428              'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
 429              'letter' => new external_value(PARAM_ALPHA, 'A letter, or either keywords: \'ALL\' or \'SPECIAL\'.'),
 430              'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
 431              'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
 432              'options' => new external_single_structure(array(
 433                  'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
 434                      ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
 435              ), 'An array of options', VALUE_DEFAULT, array())
 436          ));
 437      }
 438  
 439      /**
 440       * Browse a glossary entries by letter.
 441       *
 442       * @param int $id The glossary ID.
 443       * @param string $letter A letter, or a special keyword.
 444       * @param int $from Start returning records from here.
 445       * @param int $limit Number of records to return.
 446       * @param array $options Array of options.
 447       * @return array Containing count, entries and warnings.
 448       * @since Moodle 3.1
 449       * @throws moodle_exception
 450       * @throws invalid_parameter_exception
 451       */
 452      public static function get_entries_by_letter($id, $letter, $from, $limit, $options) {
 453          $params = self::validate_parameters(self::get_entries_by_letter_parameters(), array(
 454              'id' => $id,
 455              'letter' => $letter,
 456              'from' => $from,
 457              'limit' => $limit,
 458              'options' => $options,
 459          ));
 460          $id = $params['id'];
 461          $letter = $params['letter'];
 462          $from = $params['from'];
 463          $limit = $params['limit'];
 464          $options = $params['options'];
 465          $warnings = array();
 466  
 467          // Get and validate the glossary.
 468          list($glossary, $context) = self::validate_glossary($id);
 469  
 470          // Validate the mode.
 471          $modes = self::get_browse_modes_from_display_format($glossary->displayformat);
 472          if (!in_array('letter', $modes)) {
 473              throw new invalid_parameter_exception('invalidbrowsemode');
 474          }
 475  
 476          $entries = array();
 477          list($records, $count) = glossary_get_entries_by_letter($glossary, $context, $letter, $from, $limit, $options);
 478          foreach ($records as $key => $record) {
 479              self::fill_entry_details($record, $context);
 480              $entries[] = $record;
 481          }
 482  
 483          return array(
 484              'count' => $count,
 485              'entries' => $entries,
 486              'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
 487              'warnings' => $warnings
 488          );
 489      }
 490  
 491      /**
 492       * Returns the description of the external function return value.
 493       *
 494       * @return external_description
 495       * @since Moodle 3.1
 496       */
 497      public static function get_entries_by_letter_returns() {
 498          return new external_single_structure(array(
 499              'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
 500              'entries' => new external_multiple_structure(
 501                  self::get_entry_return_structure()
 502              ),
 503              'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
 504              'warnings' => new external_warnings()
 505          ));
 506      }
 507  
 508      /**
 509       * Returns the description of the external function parameters.
 510       *
 511       * @return external_function_parameters
 512       * @since Moodle 3.1
 513       */
 514      public static function get_entries_by_date_parameters() {
 515          return new external_function_parameters(array(
 516              'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
 517              'order' => new external_value(PARAM_ALPHA, 'Order the records by: \'CREATION\' or \'UPDATE\'.',
 518                  VALUE_DEFAULT, 'UPDATE'),
 519              'sort' => new external_value(PARAM_ALPHA, 'The direction of the order: \'ASC\' or \'DESC\'', VALUE_DEFAULT, 'DESC'),
 520              'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
 521              'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
 522              'options' => new external_single_structure(array(
 523                  'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
 524                      ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
 525              ), 'An array of options', VALUE_DEFAULT, array())
 526          ));
 527      }
 528  
 529      /**
 530       * Browse a glossary entries by date.
 531       *
 532       * @param int $id The glossary ID.
 533       * @param string $order The way to order the records.
 534       * @param string $sort The direction of the order.
 535       * @param int $from Start returning records from here.
 536       * @param int $limit Number of records to return.
 537       * @param array $options Array of options.
 538       * @return array Containing count, entries and warnings.
 539       * @since Moodle 3.1
 540       * @throws moodle_exception
 541       * @throws invalid_parameter_exception
 542       */
 543      public static function get_entries_by_date($id, $order, $sort, $from, $limit, $options) {
 544          $params = self::validate_parameters(self::get_entries_by_date_parameters(), array(
 545              'id' => $id,
 546              'order' => core_text::strtoupper($order),
 547              'sort' => core_text::strtoupper($sort),
 548              'from' => $from,
 549              'limit' => $limit,
 550              'options' => $options,
 551          ));
 552          $id = $params['id'];
 553          $order = $params['order'];
 554          $sort = $params['sort'];
 555          $from = $params['from'];
 556          $limit = $params['limit'];
 557          $options = $params['options'];
 558          $warnings = array();
 559  
 560          if (!in_array($order, array('CREATION', 'UPDATE'))) {
 561              throw new invalid_parameter_exception('invalidorder');
 562          } else if (!in_array($sort, array('ASC', 'DESC'))) {
 563              throw new invalid_parameter_exception('invalidsort');
 564          }
 565  
 566          // Get and validate the glossary.
 567          list($glossary, $context) = self::validate_glossary($id);
 568  
 569          // Validate the mode.
 570          $modes = self::get_browse_modes_from_display_format($glossary->displayformat);
 571          if (!in_array('date', $modes)) {
 572              throw new invalid_parameter_exception('invalidbrowsemode');
 573          }
 574  
 575          $entries = array();
 576          list($records, $count) = glossary_get_entries_by_date($glossary, $context, $order, $sort, $from, $limit, $options);
 577          foreach ($records as $key => $record) {
 578              self::fill_entry_details($record, $context);
 579              $entries[] = $record;
 580          }
 581  
 582          return array(
 583              'count' => $count,
 584              'entries' => $entries,
 585              'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
 586              'warnings' => $warnings
 587          );
 588      }
 589  
 590      /**
 591       * Returns the description of the external function return value.
 592       *
 593       * @return external_description
 594       * @since Moodle 3.1
 595       */
 596      public static function get_entries_by_date_returns() {
 597          return new external_single_structure(array(
 598              'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
 599              'entries' => new external_multiple_structure(
 600                  self::get_entry_return_structure()
 601              ),
 602              'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
 603              'warnings' => new external_warnings()
 604          ));
 605      }
 606  
 607      /**
 608       * Returns the description of the external function parameters.
 609       *
 610       * @return external_function_parameters
 611       * @since Moodle 3.1
 612       */
 613      public static function get_categories_parameters() {
 614          return new external_function_parameters(array(
 615              'id' => new external_value(PARAM_INT, 'The glossary ID'),
 616              'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
 617              'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20)
 618          ));
 619      }
 620  
 621      /**
 622       * Get the categories of a glossary.
 623       *
 624       * @param int $id The glossary ID.
 625       * @param int $from Start returning records from here.
 626       * @param int $limit Number of records to return.
 627       * @return array Containing count, categories and warnings.
 628       * @since Moodle 3.1
 629       * @throws moodle_exception
 630       */
 631      public static function get_categories($id, $from, $limit) {
 632          $params = self::validate_parameters(self::get_categories_parameters(), array(
 633              'id' => $id,
 634              'from' => $from,
 635              'limit' => $limit
 636          ));
 637          $id = $params['id'];
 638          $from = $params['from'];
 639          $limit = $params['limit'];
 640          $warnings = array();
 641  
 642          // Get and validate the glossary.
 643          list($glossary, $context) = self::validate_glossary($id);
 644  
 645          // Fetch the categories.
 646          $categories = array();
 647          list($records, $count) = glossary_get_categories($glossary, $from, $limit);
 648          foreach ($records as $category) {
 649              $category->name = external_format_string($category->name, $context->id);
 650              $categories[] = $category;
 651          }
 652  
 653          return array(
 654              'count' => $count,
 655              'categories' => $categories,
 656              'warnings' => array(),
 657          );
 658      }
 659  
 660      /**
 661       * Returns the description of the external function return value.
 662       *
 663       * @return external_description
 664       * @since Moodle 3.1
 665       */
 666      public static function get_categories_returns() {
 667          return new external_single_structure(array(
 668              'count' => new external_value(PARAM_INT, 'The total number of records.'),
 669              'categories' => new external_multiple_structure(
 670                  new external_single_structure(array(
 671                      'id' => new external_value(PARAM_INT, 'The category ID'),
 672                      'glossaryid' => new external_value(PARAM_INT, 'The glossary ID'),
 673                      'name' => new external_value(PARAM_RAW, 'The name of the category'),
 674                      'usedynalink' => new external_value(PARAM_BOOL, 'Whether the category is automatically linked'),
 675                  ))
 676              ),
 677              'warnings' => new external_warnings()
 678          ));
 679      }
 680  
 681      /**
 682       * Returns the description of the external function parameters.
 683       *
 684       * @return external_function_parameters
 685       * @since Moodle 3.1
 686       */
 687      public static function get_entries_by_category_parameters() {
 688          return new external_function_parameters(array(
 689              'id' => new external_value(PARAM_INT, 'The glossary ID.'),
 690              'categoryid' => new external_value(PARAM_INT, 'The category ID. Use \'' . GLOSSARY_SHOW_ALL_CATEGORIES . '\' for all' .
 691                  ' categories, or \'' . GLOSSARY_SHOW_NOT_CATEGORISED . '\' for uncategorised entries.'),
 692              'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
 693              'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
 694              'options' => new external_single_structure(array(
 695                  'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
 696                      ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
 697              ), 'An array of options', VALUE_DEFAULT, array())
 698          ));
 699      }
 700  
 701      /**
 702       * Browse a glossary entries by category.
 703       *
 704       * @param int $id The glossary ID.
 705       * @param int $categoryid The category ID.
 706       * @param int $from Start returning records from here.
 707       * @param int $limit Number of records to return.
 708       * @param array $options Array of options.
 709       * @return array Containing count, entries and warnings.
 710       * @since Moodle 3.1
 711       * @throws moodle_exception
 712       * @throws invalid_parameter_exception
 713       */
 714      public static function get_entries_by_category($id, $categoryid, $from, $limit, $options) {
 715          global $DB;
 716  
 717          $params = self::validate_parameters(self::get_entries_by_category_parameters(), array(
 718              'id' => $id,
 719              'categoryid' => $categoryid,
 720              'from' => $from,
 721              'limit' => $limit,
 722              'options' => $options,
 723          ));
 724          $id = $params['id'];
 725          $categoryid = $params['categoryid'];
 726          $from = $params['from'];
 727          $limit = $params['limit'];
 728          $options = $params['options'];
 729          $warnings = array();
 730  
 731          // Get and validate the glossary.
 732          list($glossary, $context) = self::validate_glossary($id);
 733  
 734          // Validate the mode.
 735          $modes = self::get_browse_modes_from_display_format($glossary->displayformat);
 736          if (!in_array('cat', $modes)) {
 737              throw new invalid_parameter_exception('invalidbrowsemode');
 738          }
 739  
 740          // Validate the category.
 741          if (in_array($categoryid, array(GLOSSARY_SHOW_ALL_CATEGORIES, GLOSSARY_SHOW_NOT_CATEGORISED))) {
 742              // All good.
 743          } else if (!$DB->record_exists('glossary_categories', array('id' => $categoryid, 'glossaryid' => $id))) {
 744              throw new invalid_parameter_exception('invalidcategory');
 745          }
 746  
 747          // Fetching the entries.
 748          $entries = array();
 749          list($records, $count) = glossary_get_entries_by_category($glossary, $context, $categoryid, $from, $limit, $options);
 750          foreach ($records as $key => $record) {
 751              self::fill_entry_details($record, $context);
 752              if ($record->categoryid === null) {
 753                  $record->categoryid = GLOSSARY_SHOW_NOT_CATEGORISED;
 754              }
 755              if (isset($record->categoryname)) {
 756                  $record->categoryname = external_format_string($record->categoryname, $context->id);
 757              }
 758              $entries[] = $record;
 759          }
 760  
 761          return array(
 762              'count' => $count,
 763              'entries' => $entries,
 764              'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
 765              'warnings' => $warnings
 766          );
 767      }
 768  
 769      /**
 770       * Returns the description of the external function return value.
 771       *
 772       * @return external_description
 773       * @since Moodle 3.1
 774       */
 775      public static function get_entries_by_category_returns() {
 776          return new external_single_structure(array(
 777              'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
 778              'entries' => new external_multiple_structure(
 779                  self::get_entry_return_structure(true)
 780              ),
 781              'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
 782              'warnings' => new external_warnings()
 783          ));
 784      }
 785  
 786      /**
 787       * Returns the description of the external function parameters.
 788       *
 789       * @return external_function_parameters
 790       * @since Moodle 3.1
 791       */
 792      public static function get_authors_parameters() {
 793          return new external_function_parameters(array(
 794              'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
 795              'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
 796              'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
 797              'options' => new external_single_structure(array(
 798                  'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes self even if all of their entries' .
 799                      ' require approval. When true, also includes authors only having entries pending approval.', VALUE_DEFAULT, 0)
 800              ), 'An array of options', VALUE_DEFAULT, array())
 801          ));
 802      }
 803  
 804      /**
 805       * Get the authors of a glossary.
 806       *
 807       * @param int $id The glossary ID.
 808       * @param int $from Start returning records from here.
 809       * @param int $limit Number of records to return.
 810       * @param array $options Array of options.
 811       * @return array Containing count, authors and warnings.
 812       * @since Moodle 3.1
 813       * @throws moodle_exception
 814       */
 815      public static function get_authors($id, $from, $limit, $options) {
 816          global $PAGE;
 817  
 818          $params = self::validate_parameters(self::get_authors_parameters(), array(
 819              'id' => $id,
 820              'from' => $from,
 821              'limit' => $limit,
 822              'options' => $options,
 823          ));
 824          $id = $params['id'];
 825          $from = $params['from'];
 826          $limit = $params['limit'];
 827          $options = $params['options'];
 828          $warnings = array();
 829  
 830          // Get and validate the glossary.
 831          list($glossary, $context) = self::validate_glossary($id);
 832  
 833          // Fetching the entries.
 834          list($users, $count) = glossary_get_authors($glossary, $context, $limit, $from, $options);
 835  
 836          $canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
 837          foreach ($users as $user) {
 838              $userpicture = new user_picture($user);
 839              $userpicture->size = 1;
 840  
 841              $author = new stdClass();
 842              $author->id = $user->id;
 843              $author->fullname = fullname($user, $canviewfullnames);
 844              $author->pictureurl = $userpicture->get_url($PAGE)->out(false);
 845              $authors[] = $author;
 846          }
 847          $users->close();
 848  
 849          return array(
 850              'count' => $count,
 851              'authors' => $authors,
 852              'warnings' => array(),
 853          );
 854      }
 855  
 856      /**
 857       * Returns the description of the external function return value.
 858       *
 859       * @return external_description
 860       * @since Moodle 3.1
 861       */
 862      public static function get_authors_returns() {
 863          return new external_single_structure(array(
 864              'count' => new external_value(PARAM_INT, 'The total number of records.'),
 865              'authors' => new external_multiple_structure(
 866                  new external_single_structure(array(
 867                      'id' => new external_value(PARAM_INT, 'The user ID'),
 868                      'fullname' => new external_value(PARAM_NOTAGS, 'The fullname'),
 869                      'pictureurl' => new external_value(PARAM_URL, 'The picture URL'),
 870                  ))
 871              ),
 872              'warnings' => new external_warnings()
 873          ));
 874      }
 875  
 876      /**
 877       * Returns the description of the external function parameters.
 878       *
 879       * @return external_function_parameters
 880       * @since Moodle 3.1
 881       */
 882      public static function get_entries_by_author_parameters() {
 883          return new external_function_parameters(array(
 884              'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
 885              'letter' => new external_value(PARAM_ALPHA, 'First letter of firstname or lastname, or either keywords:'
 886                  . ' \'ALL\' or \'SPECIAL\'.'),
 887              'field' => new external_value(PARAM_ALPHA, 'Search and order using: \'FIRSTNAME\' or \'LASTNAME\'', VALUE_DEFAULT,
 888                  'LASTNAME'),
 889              'sort' => new external_value(PARAM_ALPHA, 'The direction of the order: \'ASC\' or \'DESC\'', VALUE_DEFAULT, 'ASC'),
 890              'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
 891              'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
 892              'options' => new external_single_structure(array(
 893                  'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
 894                      ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
 895              ), 'An array of options', VALUE_DEFAULT, array())
 896          ));
 897      }
 898  
 899      /**
 900       * Browse a glossary entries by author.
 901       *
 902       * @param int $id The glossary ID.
 903       * @param string $letter A letter, or a special keyword.
 904       * @param string $field The field to search from.
 905       * @param string $sort The direction of the order.
 906       * @param int $from Start returning records from here.
 907       * @param int $limit Number of records to return.
 908       * @param array $options Array of options.
 909       * @return array Containing count, entries and warnings.
 910       * @since Moodle 3.1
 911       * @throws moodle_exception
 912       * @throws invalid_parameter_exception
 913       */
 914      public static function get_entries_by_author($id, $letter, $field, $sort, $from, $limit, $options) {
 915          $params = self::validate_parameters(self::get_entries_by_author_parameters(), array(
 916              'id' => $id,
 917              'letter' => $letter,
 918              'field' => core_text::strtoupper($field),
 919              'sort' => core_text::strtoupper($sort),
 920              'from' => $from,
 921              'limit' => $limit,
 922              'options' => $options,
 923          ));
 924          $id = $params['id'];
 925          $letter = $params['letter'];
 926          $field = $params['field'];
 927          $sort = $params['sort'];
 928          $from = $params['from'];
 929          $limit = $params['limit'];
 930          $options = $params['options'];
 931          $warnings = array();
 932  
 933          if (!in_array($field, array('FIRSTNAME', 'LASTNAME'))) {
 934              throw new invalid_parameter_exception('invalidfield');
 935          } else if (!in_array($sort, array('ASC', 'DESC'))) {
 936              throw new invalid_parameter_exception('invalidsort');
 937          }
 938  
 939          // Get and validate the glossary.
 940          list($glossary, $context) = self::validate_glossary($id);
 941  
 942          // Validate the mode.
 943          $modes = self::get_browse_modes_from_display_format($glossary->displayformat);
 944          if (!in_array('author', $modes)) {
 945              throw new invalid_parameter_exception('invalidbrowsemode');
 946          }
 947  
 948          // Fetching the entries.
 949          $entries = array();
 950          list($records, $count) = glossary_get_entries_by_author($glossary, $context, $letter, $field, $sort, $from, $limit,
 951              $options);
 952          foreach ($records as $key => $record) {
 953              self::fill_entry_details($record, $context);
 954              $entries[] = $record;
 955          }
 956  
 957          return array(
 958              'count' => $count,
 959              'entries' => $entries,
 960              'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
 961              'warnings' => $warnings
 962          );
 963      }
 964  
 965      /**
 966       * Returns the description of the external function return value.
 967       *
 968       * @return external_description
 969       * @since Moodle 3.1
 970       */
 971      public static function get_entries_by_author_returns() {
 972          return new external_single_structure(array(
 973              'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
 974              'entries' => new external_multiple_structure(
 975                  self::get_entry_return_structure()
 976              ),
 977              'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
 978              'warnings' => new external_warnings()
 979          ));
 980      }
 981  
 982      /**
 983       * Returns the description of the external function parameters.
 984       *
 985       * @return external_function_parameters
 986       * @since Moodle 3.1
 987       */
 988      public static function get_entries_by_author_id_parameters() {
 989          return new external_function_parameters(array(
 990              'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
 991              'authorid' => new external_value(PARAM_INT, 'The author ID'),
 992              'order' => new external_value(PARAM_ALPHA, 'Order by: \'CONCEPT\', \'CREATION\' or \'UPDATE\'', VALUE_DEFAULT,
 993                  'CONCEPT'),
 994              'sort' => new external_value(PARAM_ALPHA, 'The direction of the order: \'ASC\' or \'DESC\'', VALUE_DEFAULT, 'ASC'),
 995              'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
 996              'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
 997              'options' => new external_single_structure(array(
 998                  'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
 999                      ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
1000              ), 'An array of options', VALUE_DEFAULT, array())
1001          ));
1002      }
1003  
1004      /**
1005       * Browse a glossary entries by author.
1006       *
1007       * @param int $id The glossary ID.
1008       * @param int $authorid The author ID.
1009       * @param string $order The way to order the results.
1010       * @param string $sort The direction of the order.
1011       * @param int $from Start returning records from here.
1012       * @param int $limit Number of records to return.
1013       * @param array $options Array of options.
1014       * @return array Containing count, entries and warnings.
1015       * @since Moodle 3.1
1016       * @throws moodle_exception
1017       * @throws invalid_parameter_exception
1018       */
1019      public static function get_entries_by_author_id($id, $authorid, $order, $sort, $from, $limit, $options) {
1020          $params = self::validate_parameters(self::get_entries_by_author_id_parameters(), array(
1021              'id' => $id,
1022              'authorid' => $authorid,
1023              'order' => core_text::strtoupper($order),
1024              'sort' => core_text::strtoupper($sort),
1025              'from' => $from,
1026              'limit' => $limit,
1027              'options' => $options,
1028          ));
1029          $id = $params['id'];
1030          $authorid = $params['authorid'];
1031          $order = $params['order'];
1032          $sort = $params['sort'];
1033          $from = $params['from'];
1034          $limit = $params['limit'];
1035          $options = $params['options'];
1036          $warnings = array();
1037  
1038          if (!in_array($order, array('CONCEPT', 'CREATION', 'UPDATE'))) {
1039              throw new invalid_parameter_exception('invalidorder');
1040          } else if (!in_array($sort, array('ASC', 'DESC'))) {
1041              throw new invalid_parameter_exception('invalidsort');
1042          }
1043  
1044          // Get and validate the glossary.
1045          list($glossary, $context) = self::validate_glossary($id);
1046  
1047          // Validate the mode.
1048          $modes = self::get_browse_modes_from_display_format($glossary->displayformat);
1049          if (!in_array('author', $modes)) {
1050              throw new invalid_parameter_exception('invalidbrowsemode');
1051          }
1052  
1053          // Fetching the entries.
1054          $entries = array();
1055          list($records, $count) = glossary_get_entries_by_author_id($glossary, $context, $authorid, $order, $sort, $from,
1056              $limit, $options);
1057          foreach ($records as $key => $record) {
1058              self::fill_entry_details($record, $context);
1059              $entries[] = $record;
1060          }
1061  
1062          return array(
1063              'count' => $count,
1064              'entries' => $entries,
1065              'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
1066              'warnings' => $warnings
1067          );
1068      }
1069  
1070      /**
1071       * Returns the description of the external function return value.
1072       *
1073       * @return external_description
1074       * @since Moodle 3.1
1075       */
1076      public static function get_entries_by_author_id_returns() {
1077          return new external_single_structure(array(
1078              'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
1079              'entries' => new external_multiple_structure(
1080                  self::get_entry_return_structure()
1081              ),
1082              'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
1083              'warnings' => new external_warnings()
1084          ));
1085      }
1086  
1087      /**
1088       * Returns the description of the external function parameters.
1089       *
1090       * @return external_function_parameters
1091       * @since Moodle 3.1
1092       */
1093      public static function get_entries_by_search_parameters() {
1094          return new external_function_parameters(array(
1095              'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
1096              'query' => new external_value(PARAM_NOTAGS, 'The query string'),
1097              'fullsearch' => new external_value(PARAM_BOOL, 'The query', VALUE_DEFAULT, 1),
1098              'order' => new external_value(PARAM_ALPHA, 'Order by: \'CONCEPT\', \'CREATION\' or \'UPDATE\'', VALUE_DEFAULT,
1099                  'CONCEPT'),
1100              'sort' => new external_value(PARAM_ALPHA, 'The direction of the order: \'ASC\' or \'DESC\'', VALUE_DEFAULT, 'ASC'),
1101              'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
1102              'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
1103              'options' => new external_single_structure(array(
1104                  'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
1105                      ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
1106              ), 'An array of options', VALUE_DEFAULT, array())
1107          ));
1108      }
1109  
1110      /**
1111       * Browse a glossary entries using the search.
1112       *
1113       * @param int $id The glossary ID.
1114       * @param string $query The search query.
1115       * @param bool $fullsearch Whether or not full search is required.
1116       * @param string $order The way to order the results.
1117       * @param string $sort The direction of the order.
1118       * @param int $from Start returning records from here.
1119       * @param int $limit Number of records to return.
1120       * @param array $options Array of options.
1121       * @return array Containing count, entries and warnings.
1122       * @since Moodle 3.1
1123       * @throws moodle_exception
1124       * @throws invalid_parameter_exception
1125       */
1126      public static function get_entries_by_search($id, $query, $fullsearch, $order, $sort, $from, $limit, $options) {
1127          $params = self::validate_parameters(self::get_entries_by_search_parameters(), array(
1128              'id' => $id,
1129              'query' => $query,
1130              'fullsearch' => $fullsearch,
1131              'order' => core_text::strtoupper($order),
1132              'sort' => core_text::strtoupper($sort),
1133              'from' => $from,
1134              'limit' => $limit,
1135              'options' => $options,
1136          ));
1137          $id = $params['id'];
1138          $query = $params['query'];
1139          $fullsearch = $params['fullsearch'];
1140          $order = $params['order'];
1141          $sort = $params['sort'];
1142          $from = $params['from'];
1143          $limit = $params['limit'];
1144          $options = $params['options'];
1145          $warnings = array();
1146  
1147          if (!in_array($order, array('CONCEPT', 'CREATION', 'UPDATE'))) {
1148              throw new invalid_parameter_exception('invalidorder');
1149          } else if (!in_array($sort, array('ASC', 'DESC'))) {
1150              throw new invalid_parameter_exception('invalidsort');
1151          }
1152  
1153          // Get and validate the glossary.
1154          list($glossary, $context) = self::validate_glossary($id);
1155  
1156          // Fetching the entries.
1157          $entries = array();
1158          list($records, $count) = glossary_get_entries_by_search($glossary, $context, $query, $fullsearch, $order, $sort, $from,
1159              $limit, $options);
1160          foreach ($records as $key => $record) {
1161              self::fill_entry_details($record, $context);
1162              $entries[] = $record;
1163          }
1164  
1165          return array(
1166              'count' => $count,
1167              'entries' => $entries,
1168              'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
1169              'warnings' => $warnings
1170          );
1171      }
1172  
1173      /**
1174       * Returns the description of the external function return value.
1175       *
1176       * @return external_description
1177       * @since Moodle 3.1
1178       */
1179      public static function get_entries_by_search_returns() {
1180          return new external_single_structure(array(
1181              'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
1182              'entries' => new external_multiple_structure(
1183                  self::get_entry_return_structure()
1184              ),
1185              'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
1186              'warnings' => new external_warnings()
1187          ));
1188      }
1189  
1190      /**
1191       * Returns the description of the external function parameters.
1192       *
1193       * @return external_function_parameters
1194       * @since Moodle 3.1
1195       */
1196      public static function get_entries_by_term_parameters() {
1197          return new external_function_parameters(array(
1198              'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
1199              'term' => new external_value(PARAM_NOTAGS, 'The entry concept, or alias'),
1200              'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
1201              'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
1202              'options' => new external_single_structure(array(
1203                  'includenotapproved' => new external_value(PARAM_BOOL, 'When false, includes the non-approved entries created by' .
1204                      ' the user. When true, also includes the ones that the user has the permission to approve.', VALUE_DEFAULT, 0)
1205              ), 'An array of options', VALUE_DEFAULT, array())
1206          ));
1207      }
1208  
1209      /**
1210       * Browse a glossary entries using a term matching the concept or alias.
1211       *
1212       * @param int $id The glossary ID.
1213       * @param string $term The term.
1214       * @param int $from Start returning records from here.
1215       * @param int $limit Number of records to return.
1216       * @param array $options Array of options.
1217       * @return array Containing count, entries and warnings.
1218       * @since Moodle 3.1
1219       * @throws moodle_exception
1220       */
1221      public static function get_entries_by_term($id, $term, $from, $limit, $options) {
1222          $params = self::validate_parameters(self::get_entries_by_term_parameters(), array(
1223              'id' => $id,
1224              'term' => $term,
1225              'from' => $from,
1226              'limit' => $limit,
1227              'options' => $options,
1228          ));
1229          $id = $params['id'];
1230          $term = $params['term'];
1231          $from = $params['from'];
1232          $limit = $params['limit'];
1233          $options = $params['options'];
1234          $warnings = array();
1235  
1236          // Get and validate the glossary.
1237          list($glossary, $context) = self::validate_glossary($id);
1238  
1239          // Fetching the entries.
1240          $entries = array();
1241          list($records, $count) = glossary_get_entries_by_term($glossary, $context, $term, $from, $limit, $options);
1242          foreach ($records as $key => $record) {
1243              self::fill_entry_details($record, $context);
1244              $entries[] = $record;
1245          }
1246  
1247          return array(
1248              'count' => $count,
1249              'entries' => $entries,
1250              'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
1251              'warnings' => $warnings
1252          );
1253      }
1254  
1255      /**
1256       * Returns the description of the external function return value.
1257       *
1258       * @return external_description
1259       * @since Moodle 3.1
1260       */
1261      public static function get_entries_by_term_returns() {
1262          return new external_single_structure(array(
1263              'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
1264              'entries' => new external_multiple_structure(
1265                  self::get_entry_return_structure()
1266              ),
1267              'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
1268              'warnings' => new external_warnings()
1269          ));
1270      }
1271  
1272      /**
1273       * Returns the description of the external function parameters.
1274       *
1275       * @return external_function_parameters
1276       * @since Moodle 3.1
1277       */
1278      public static function get_entries_to_approve_parameters() {
1279          return new external_function_parameters(array(
1280              'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
1281              'letter' => new external_value(PARAM_ALPHA, 'A letter, or either keywords: \'ALL\' or \'SPECIAL\'.'),
1282              'order' => new external_value(PARAM_ALPHA, 'Order by: \'CONCEPT\', \'CREATION\' or \'UPDATE\'', VALUE_DEFAULT,
1283                  'CONCEPT'),
1284              'sort' => new external_value(PARAM_ALPHA, 'The direction of the order: \'ASC\' or \'DESC\'', VALUE_DEFAULT, 'ASC'),
1285              'from' => new external_value(PARAM_INT, 'Start returning records from here', VALUE_DEFAULT, 0),
1286              'limit' => new external_value(PARAM_INT, 'Number of records to return', VALUE_DEFAULT, 20),
1287              'options' => new external_single_structure(array(), 'An array of options', VALUE_DEFAULT, array())
1288          ));
1289      }
1290  
1291      /**
1292       * Browse a glossary entries using a term matching the concept or alias.
1293       *
1294       * @param int $id The glossary ID.
1295       * @param string $letter A letter, or a special keyword.
1296       * @param string $order The way to order the records.
1297       * @param string $sort The direction of the order.
1298       * @param int $from Start returning records from here.
1299       * @param int $limit Number of records to return.
1300       * @return array Containing count, entries and warnings.
1301       * @since Moodle 3.1
1302       * @throws moodle_exception
1303       */
1304      public static function get_entries_to_approve($id, $letter, $order, $sort, $from, $limit) {
1305          $params = self::validate_parameters(self::get_entries_to_approve_parameters(), array(
1306              'id' => $id,
1307              'letter' => $letter,
1308              'order' => $order,
1309              'sort' => $sort,
1310              'from' => $from,
1311              'limit' => $limit
1312          ));
1313          $id = $params['id'];
1314          $letter = $params['letter'];
1315          $order = $params['order'];
1316          $sort = $params['sort'];
1317          $from = $params['from'];
1318          $limit = $params['limit'];
1319          $warnings = array();
1320  
1321          // Get and validate the glossary.
1322          list($glossary, $context) = self::validate_glossary($id);
1323  
1324          // Check the permissions.
1325          require_capability('mod/glossary:approve', $context);
1326  
1327          // Fetching the entries.
1328          $entries = array();
1329          list($records, $count) = glossary_get_entries_to_approve($glossary, $context, $letter, $order, $sort, $from, $limit);
1330          foreach ($records as $key => $record) {
1331              self::fill_entry_details($record, $context);
1332              $entries[] = $record;
1333          }
1334  
1335          return array(
1336              'count' => $count,
1337              'entries' => $entries,
1338              'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries),
1339              'warnings' => $warnings
1340          );
1341      }
1342  
1343      /**
1344       * Returns the description of the external function return value.
1345       *
1346       * @return external_description
1347       * @since Moodle 3.1
1348       */
1349      public static function get_entries_to_approve_returns() {
1350          return new external_single_structure(array(
1351              'count' => new external_value(PARAM_INT, 'The total number of records matching the request.'),
1352              'entries' => new external_multiple_structure(
1353                  self::get_entry_return_structure()
1354              ),
1355              'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
1356              'warnings' => new external_warnings()
1357          ));
1358      }
1359  
1360      /**
1361       * Returns the description of the external function parameters.
1362       *
1363       * @return external_function_parameters
1364       * @since Moodle 3.1
1365       */
1366      public static function get_entry_by_id_parameters() {
1367          return new external_function_parameters(array(
1368              'id' => new external_value(PARAM_INT, 'Glossary entry ID'),
1369          ));
1370      }
1371  
1372      /**
1373       * Get an entry.
1374       *
1375       * @param int $id The entry ID.
1376       * @return array Containing entry and warnings.
1377       * @since Moodle 3.1
1378       * @throws moodle_exception
1379       * @throws invalid_parameter_exception
1380       */
1381      public static function get_entry_by_id($id) {
1382          global $DB, $USER;
1383  
1384          $params = self::validate_parameters(self::get_entry_by_id_parameters(), array('id' => $id));
1385          $id = $params['id'];
1386          $warnings = array();
1387  
1388          // Get and validate the glossary.
1389          $entry = $DB->get_record('glossary_entries', array('id' => $id), '*', MUST_EXIST);
1390          list($glossary, $context, $course, $cm) = self::validate_glossary($entry->glossaryid);
1391  
1392          if (empty($entry->approved) && $entry->userid != $USER->id && !has_capability('mod/glossary:approve', $context)) {
1393              throw new invalid_parameter_exception('invalidentry');
1394          }
1395  
1396          $entry = glossary_get_entry_by_id($id);
1397          self::fill_entry_details($entry, $context);
1398  
1399          // Permissions (for entry edition).
1400          $permissions = [
1401              'candelete' => mod_glossary_can_delete_entry($entry, $glossary, $context),
1402              'canupdate' => mod_glossary_can_update_entry($entry, $glossary, $context, $cm),
1403          ];
1404  
1405          return array(
1406              'entry' => $entry,
1407              'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry',
1408                  array($entry)),
1409              'permissions' => $permissions,
1410              'warnings' => $warnings
1411          );
1412      }
1413  
1414      /**
1415       * Returns the description of the external function return value.
1416       *
1417       * @return external_description
1418       * @since Moodle 3.1
1419       */
1420      public static function get_entry_by_id_returns() {
1421          return new external_single_structure(array(
1422              'entry' => self::get_entry_return_structure(),
1423              'ratinginfo' => \core_rating\external\util::external_ratings_structure(),
1424              'permissions' => new external_single_structure(
1425                  [
1426                      'candelete' => new external_value(PARAM_BOOL, 'Whether the user can delete the entry.'),
1427                      'canupdate' => new external_value(PARAM_BOOL, 'Whether the user can update the entry.'),
1428                  ],
1429                  'User permissions for the managing the entry.', VALUE_OPTIONAL
1430              ),
1431              'warnings' => new external_warnings()
1432          ));
1433      }
1434  
1435      /**
1436       * Returns the description of the external function parameters.
1437       *
1438       * @return external_function_parameters
1439       * @since Moodle 3.2
1440       */
1441      public static function add_entry_parameters() {
1442          return new external_function_parameters(array(
1443              'glossaryid' => new external_value(PARAM_INT, 'Glossary id'),
1444              'concept' => new external_value(PARAM_TEXT, 'Glossary concept'),
1445              'definition' => new external_value(PARAM_RAW, 'Glossary concept definition'),
1446              'definitionformat' => new external_format_value('definition'),
1447              'options' => new external_multiple_structure (
1448                  new external_single_structure(
1449                      array(
1450                          'name' => new external_value(PARAM_ALPHANUM,
1451                              'The allowed keys (value format) are:
1452                              inlineattachmentsid (int); the draft file area id for inline attachments
1453                              attachmentsid (int); the draft file area id for attachments
1454                              categories (comma separated int); comma separated category ids
1455                              aliases (comma separated str); comma separated aliases
1456                              usedynalink (bool); whether the entry should be automatically linked.
1457                              casesensitive (bool); whether the entry is case sensitive.
1458                              fullmatch (bool); whether to match whole words only.'),
1459                          'value' => new external_value(PARAM_RAW, 'the value of the option (validated inside the function)')
1460                      )
1461                  ), 'Optional settings', VALUE_DEFAULT, array()
1462              )
1463          ));
1464      }
1465  
1466  
1467      /**
1468       * Add a new entry to a given glossary.
1469       *
1470       * @param int $glossaryid the glosary id
1471       * @param string $concept    the glossary concept
1472       * @param string $definition the concept definition
1473       * @param int $definitionformat the concept definition format
1474       * @param array  $options    additional settings
1475       * @return array Containing entry and warnings.
1476       * @since Moodle 3.2
1477       * @throws moodle_exception
1478       * @throws invalid_parameter_exception
1479       */
1480      public static function add_entry($glossaryid, $concept, $definition, $definitionformat, $options = array()) {
1481          global $CFG;
1482  
1483          $params = self::validate_parameters(self::add_entry_parameters(), array(
1484              'glossaryid' => $glossaryid,
1485              'concept' => $concept,
1486              'definition' => $definition,
1487              'definitionformat' => $definitionformat,
1488              'options' => $options,
1489          ));
1490          $warnings = array();
1491  
1492          // Get and validate the glossary.
1493          list($glossary, $context, $course, $cm) = self::validate_glossary($params['glossaryid']);
1494          require_capability('mod/glossary:write', $context);
1495  
1496          if (!$glossary->allowduplicatedentries) {
1497              if (glossary_concept_exists($glossary, $params['concept'])) {
1498                  throw new moodle_exception('errconceptalreadyexists', 'glossary');
1499              }
1500          }
1501  
1502          // Prepare the entry object.
1503          $entry = new stdClass;
1504          $entry->id = null;
1505          $entry->aliases = '';
1506          $entry->usedynalink = $CFG->glossary_linkentries;
1507          $entry->casesensitive = $CFG->glossary_casesensitive;
1508          $entry->fullmatch = $CFG->glossary_fullmatch;
1509          $entry->concept = $params['concept'];
1510          $entry->definition_editor = array(
1511              'text' => $params['definition'],
1512              'format' => $params['definitionformat'],
1513          );
1514          // Options.
1515          foreach ($params['options'] as $option) {
1516              $name = trim($option['name']);
1517              switch ($name) {
1518                  case 'inlineattachmentsid':
1519                      $entry->definition_editor['itemid'] = clean_param($option['value'], PARAM_INT);
1520                      break;
1521                  case 'attachmentsid':
1522                      $entry->attachment_filemanager = clean_param($option['value'], PARAM_INT);
1523                      break;
1524                  case 'categories':
1525                      $entry->categories = clean_param($option['value'], PARAM_SEQUENCE);
1526                      $entry->categories = explode(',', $entry->categories);
1527                      break;
1528                  case 'aliases':
1529                      $entry->aliases = clean_param($option['value'], PARAM_NOTAGS);
1530                      // Convert to the expected format.
1531                      $entry->aliases = str_replace(",", "\n", $entry->aliases);
1532                      break;
1533                  case 'usedynalink':
1534                  case 'casesensitive':
1535                  case 'fullmatch':
1536                      // Only allow if linking is enabled.
1537                      if ($glossary->usedynalink) {
1538                          $entry->{$name} = clean_param($option['value'], PARAM_BOOL);
1539                      }
1540                      break;
1541                  default:
1542                      throw new moodle_exception('errorinvalidparam', 'webservice', '', $name);
1543              }
1544          }
1545  
1546          $entry = glossary_edit_entry($entry, $course, $cm, $glossary, $context);
1547  
1548          return array(
1549              'entryid' => $entry->id,
1550              'warnings' => $warnings
1551          );
1552      }
1553  
1554      /**
1555       * Returns the description of the external function return value.
1556       *
1557       * @return external_description
1558       * @since Moodle 3.2
1559       */
1560      public static function add_entry_returns() {
1561          return new external_single_structure(array(
1562              'entryid' => new external_value(PARAM_INT, 'New glossary entry ID'),
1563              'warnings' => new external_warnings()
1564          ));
1565      }
1566  
1567  }