Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

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