Search moodle.org's
Developer Documentation

See Release Notes

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

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

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