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 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   * External cohort API
  19   *
  20   * @package    core_cohort
  21   * @category   external
  22   * @copyright  MediaTouch 2000 srl
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  require_once("$CFG->libdir/externallib.php");
  29  
  30  class core_cohort_external extends external_api {
  31  
  32      /**
  33       * Returns description of method parameters
  34       *
  35       * @return external_function_parameters
  36       * @since Moodle 2.5
  37       */
  38      public static function create_cohorts_parameters() {
  39          return new external_function_parameters(
  40              array(
  41                  'cohorts' => new external_multiple_structure(
  42                      new external_single_structure(
  43                          array(
  44                              'categorytype' => new external_single_structure(
  45                                  array(
  46                                      'type' => new external_value(PARAM_TEXT, 'the name of the field: id (numeric value
  47                                          of course category id) or idnumber (alphanumeric value of idnumber course category)
  48                                          or system (value ignored)'),
  49                                      'value' => new external_value(PARAM_RAW, 'the value of the categorytype')
  50                                  )
  51                              ),
  52                              'name' => new external_value(PARAM_RAW, 'cohort name'),
  53                              'idnumber' => new external_value(PARAM_RAW, 'cohort idnumber'),
  54                              'description' => new external_value(PARAM_RAW, 'cohort description', VALUE_OPTIONAL),
  55                              'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
  56                              'visible' => new external_value(PARAM_BOOL, 'cohort visible', VALUE_OPTIONAL, true),
  57                              'theme' => new external_value(PARAM_THEME,
  58                                  'the cohort theme. The allowcohortthemes setting must be enabled on Moodle',
  59                                  VALUE_OPTIONAL
  60                              ),
  61                          )
  62                      )
  63                  )
  64              )
  65          );
  66      }
  67  
  68      /**
  69       * Create one or more cohorts
  70       *
  71       * @param array $cohorts An array of cohorts to create.
  72       * @return array An array of arrays
  73       * @since Moodle 2.5
  74       */
  75      public static function create_cohorts($cohorts) {
  76          global $CFG, $DB;
  77          require_once("$CFG->dirroot/cohort/lib.php");
  78  
  79          $params = self::validate_parameters(self::create_cohorts_parameters(), array('cohorts' => $cohorts));
  80  
  81          $availablethemes = cohort_get_list_of_themes();
  82  
  83          $transaction = $DB->start_delegated_transaction();
  84  
  85          $syscontext = context_system::instance();
  86          $cohortids = array();
  87  
  88          foreach ($params['cohorts'] as $cohort) {
  89              $cohort = (object)$cohort;
  90  
  91              // Category type (context id).
  92              $categorytype = $cohort->categorytype;
  93              if (!in_array($categorytype['type'], array('idnumber', 'id', 'system'))) {
  94                  throw new invalid_parameter_exception('category type must be id, idnumber or system:' . $categorytype['type']);
  95              }
  96              if ($categorytype['type'] === 'system') {
  97                  $cohort->contextid = $syscontext->id;
  98              } else if ($catid = $DB->get_field('course_categories', 'id', array($categorytype['type'] => $categorytype['value']))) {
  99                  $catcontext = context_coursecat::instance($catid);
 100                  $cohort->contextid = $catcontext->id;
 101              } else {
 102                  throw new invalid_parameter_exception('category not exists: category '
 103                      .$categorytype['type'].' = '.$categorytype['value']);
 104              }
 105              // Make sure that the idnumber doesn't already exist.
 106              if ($DB->record_exists('cohort', array('idnumber' => $cohort->idnumber))) {
 107                  throw new invalid_parameter_exception('record already exists: idnumber='.$cohort->idnumber);
 108              }
 109              $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
 110              if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
 111                  throw new invalid_parameter_exception('Invalid context');
 112              }
 113              self::validate_context($context);
 114              require_capability('moodle/cohort:manage', $context);
 115  
 116              // Make sure theme is valid.
 117              if (isset($cohort->theme)) {
 118                  if (!empty($CFG->allowcohortthemes)) {
 119                      if (empty($availablethemes[$cohort->theme])) {
 120                          throw new moodle_exception('errorinvalidparam', 'webservice', '', 'theme');
 121                      }
 122                  }
 123              }
 124  
 125              // Validate format.
 126              $cohort->descriptionformat = external_validate_format($cohort->descriptionformat);
 127              $cohort->id = cohort_add_cohort($cohort);
 128  
 129              list($cohort->description, $cohort->descriptionformat) =
 130                  external_format_text($cohort->description, $cohort->descriptionformat,
 131                          $context->id, 'cohort', 'description', $cohort->id);
 132              $cohortids[] = (array)$cohort;
 133          }
 134          $transaction->allow_commit();
 135  
 136          return $cohortids;
 137      }
 138  
 139      /**
 140       * Returns description of method result value
 141       *
 142       * @return external_description
 143       * @since Moodle 2.5
 144       */
 145      public static function create_cohorts_returns() {
 146          return new external_multiple_structure(
 147              new external_single_structure(
 148                  array(
 149                      'id' => new external_value(PARAM_INT, 'cohort id'),
 150                      'name' => new external_value(PARAM_RAW, 'cohort name'),
 151                      'idnumber' => new external_value(PARAM_RAW, 'cohort idnumber'),
 152                      'description' => new external_value(PARAM_RAW, 'cohort description'),
 153                      'descriptionformat' => new external_format_value('description'),
 154                      'visible' => new external_value(PARAM_BOOL, 'cohort visible'),
 155                      'theme' => new external_value(PARAM_THEME, 'cohort theme', VALUE_OPTIONAL),
 156                  )
 157              )
 158          );
 159      }
 160  
 161      /**
 162       * Returns description of method parameters
 163       *
 164       * @return external_function_parameters
 165       * @since Moodle 2.5
 166       */
 167      public static function delete_cohorts_parameters() {
 168          return new external_function_parameters(
 169              array(
 170                  'cohortids' => new external_multiple_structure(new external_value(PARAM_INT, 'cohort ID')),
 171              )
 172          );
 173      }
 174  
 175      /**
 176       * Delete cohorts
 177       *
 178       * @param array $cohortids
 179       * @return null
 180       * @since Moodle 2.5
 181       */
 182      public static function delete_cohorts($cohortids) {
 183          global $CFG, $DB;
 184          require_once("$CFG->dirroot/cohort/lib.php");
 185  
 186          $params = self::validate_parameters(self::delete_cohorts_parameters(), array('cohortids' => $cohortids));
 187  
 188          $transaction = $DB->start_delegated_transaction();
 189  
 190          foreach ($params['cohortids'] as $cohortid) {
 191              // Validate params.
 192              $cohortid = validate_param($cohortid, PARAM_INT);
 193              $cohort = $DB->get_record('cohort', array('id' => $cohortid), '*', MUST_EXIST);
 194  
 195              // Now security checks.
 196              $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
 197              if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
 198                  throw new invalid_parameter_exception('Invalid context');
 199              }
 200              self::validate_context($context);
 201              require_capability('moodle/cohort:manage', $context);
 202              cohort_delete_cohort($cohort);
 203          }
 204          $transaction->allow_commit();
 205  
 206          return null;
 207      }
 208  
 209      /**
 210       * Returns description of method result value
 211       *
 212       * @return null
 213       * @since Moodle 2.5
 214       */
 215      public static function delete_cohorts_returns() {
 216          return null;
 217      }
 218  
 219      /**
 220       * Returns description of method parameters
 221       *
 222       * @return external_function_parameters
 223       * @since Moodle 2.5
 224       */
 225      public static function get_cohorts_parameters() {
 226          return new external_function_parameters(
 227              array(
 228                  'cohortids' => new external_multiple_structure(new external_value(PARAM_INT, 'Cohort ID')
 229                      , 'List of cohort id. A cohort id is an integer.', VALUE_DEFAULT, array()),
 230              )
 231          );
 232      }
 233  
 234      /**
 235       * Get cohorts definition specified by ids
 236       *
 237       * @param array $cohortids array of cohort ids
 238       * @return array of cohort objects (id, courseid, name)
 239       * @since Moodle 2.5
 240       */
 241      public static function get_cohorts($cohortids = array()) {
 242          global $DB, $CFG;
 243  
 244          $params = self::validate_parameters(self::get_cohorts_parameters(), array('cohortids' => $cohortids));
 245  
 246          if (empty($cohortids)) {
 247              $cohorts = $DB->get_records('cohort');
 248          } else {
 249              $cohorts = $DB->get_records_list('cohort', 'id', $params['cohortids']);
 250          }
 251  
 252          $cohortsinfo = array();
 253          foreach ($cohorts as $cohort) {
 254              // Now security checks.
 255              $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
 256              if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
 257                  throw new invalid_parameter_exception('Invalid context');
 258              }
 259              self::validate_context($context);
 260              if (!has_any_capability(array('moodle/cohort:manage', 'moodle/cohort:view'), $context)) {
 261                  throw new required_capability_exception($context, 'moodle/cohort:view', 'nopermissions', '');
 262              }
 263  
 264              // Only return theme when $CFG->allowcohortthemes is enabled.
 265              if (!empty($cohort->theme) && empty($CFG->allowcohortthemes)) {
 266                  $cohort->theme = null;
 267              }
 268  
 269              list($cohort->description, $cohort->descriptionformat) =
 270                  external_format_text($cohort->description, $cohort->descriptionformat,
 271                          $context->id, 'cohort', 'description', $cohort->id);
 272  
 273              $cohortsinfo[] = (array) $cohort;
 274          }
 275          return $cohortsinfo;
 276      }
 277  
 278  
 279      /**
 280       * Returns description of method result value
 281       *
 282       * @return external_description
 283       * @since Moodle 2.5
 284       */
 285      public static function get_cohorts_returns() {
 286          return new external_multiple_structure(
 287              new external_single_structure(
 288                  array(
 289                      'id' => new external_value(PARAM_INT, 'ID of the cohort'),
 290                      'name' => new external_value(PARAM_RAW, 'cohort name'),
 291                      'idnumber' => new external_value(PARAM_RAW, 'cohort idnumber'),
 292                      'description' => new external_value(PARAM_RAW, 'cohort description'),
 293                      'descriptionformat' => new external_format_value('description'),
 294                      'visible' => new external_value(PARAM_BOOL, 'cohort visible'),
 295                      'theme' => new external_value(PARAM_THEME, 'cohort theme', VALUE_OPTIONAL),
 296                  )
 297              )
 298          );
 299      }
 300  
 301      /**
 302       * Returns the description of external function parameters.
 303       *
 304       * @return external_function_parameters
 305       */
 306      public static function search_cohorts_parameters() {
 307          $query = new external_value(
 308              PARAM_RAW,
 309              'Query string'
 310          );
 311          $includes = new external_value(
 312              PARAM_ALPHA,
 313              'What other contexts to fetch the frameworks from. (all, parents, self)',
 314              VALUE_DEFAULT,
 315              'parents'
 316          );
 317          $limitfrom = new external_value(
 318              PARAM_INT,
 319              'limitfrom we are fetching the records from',
 320              VALUE_DEFAULT,
 321              0
 322          );
 323          $limitnum = new external_value(
 324              PARAM_INT,
 325              'Number of records to fetch',
 326              VALUE_DEFAULT,
 327              25
 328          );
 329          return new external_function_parameters(array(
 330              'query' => $query,
 331              'context' => self::get_context_parameters(),
 332              'includes' => $includes,
 333              'limitfrom' => $limitfrom,
 334              'limitnum' => $limitnum
 335          ));
 336      }
 337  
 338      /**
 339       * Search cohorts.
 340       *
 341       * @param string $query
 342       * @param array $context
 343       * @param string $includes
 344       * @param int $limitfrom
 345       * @param int $limitnum
 346       * @return array
 347       */
 348      public static function search_cohorts($query, $context, $includes = 'parents', $limitfrom = 0, $limitnum = 25) {
 349          global $CFG;
 350          require_once($CFG->dirroot . '/cohort/lib.php');
 351  
 352          $params = self::validate_parameters(self::search_cohorts_parameters(), array(
 353              'query' => $query,
 354              'context' => $context,
 355              'includes' => $includes,
 356              'limitfrom' => $limitfrom,
 357              'limitnum' => $limitnum,
 358          ));
 359          $query = $params['query'];
 360          $includes = $params['includes'];
 361          $context = self::get_context_from_params($params['context']);
 362          $limitfrom = $params['limitfrom'];
 363          $limitnum = $params['limitnum'];
 364  
 365          self::validate_context($context);
 366  
 367          $manager = has_capability('moodle/cohort:manage', $context);
 368          if (!$manager) {
 369              require_capability('moodle/cohort:view', $context);
 370          }
 371  
 372          // TODO Make this more efficient.
 373          if ($includes == 'self') {
 374              $results = cohort_get_cohorts($context->id, $limitfrom, $limitnum, $query);
 375              $results = $results['cohorts'];
 376          } else if ($includes == 'parents') {
 377              $results = cohort_get_cohorts($context->id, $limitfrom, $limitnum, $query);
 378              $results = $results['cohorts'];
 379              if (!$context instanceof context_system) {
 380                  $results = array_merge($results, cohort_get_available_cohorts($context, COHORT_ALL, $limitfrom, $limitnum, $query));
 381              }
 382          } else if ($includes == 'all') {
 383              $results = cohort_get_all_cohorts($limitfrom, $limitnum, $query);
 384              $results = $results['cohorts'];
 385          } else {
 386              throw new coding_exception('Invalid parameter value for \'includes\'.');
 387          }
 388  
 389          $cohorts = array();
 390          foreach ($results as $key => $cohort) {
 391              $cohortcontext = context::instance_by_id($cohort->contextid);
 392  
 393              // Only return theme when $CFG->allowcohortthemes is enabled.
 394              if (!empty($cohort->theme) && empty($CFG->allowcohortthemes)) {
 395                  $cohort->theme = null;
 396              }
 397  
 398              if (!isset($cohort->description)) {
 399                  $cohort->description = '';
 400              }
 401              if (!isset($cohort->descriptionformat)) {
 402                  $cohort->descriptionformat = FORMAT_PLAIN;
 403              }
 404  
 405              list($cohort->description, $cohort->descriptionformat) =
 406                  external_format_text($cohort->description, $cohort->descriptionformat,
 407                          $cohortcontext->id, 'cohort', 'description', $cohort->id);
 408  
 409              $cohorts[$key] = $cohort;
 410          }
 411  
 412          return array('cohorts' => $cohorts);
 413      }
 414  
 415      /**
 416       * Returns description of external function result value.
 417       *
 418       * @return external_description
 419       */
 420      public static function search_cohorts_returns() {
 421          return new external_single_structure(array(
 422              'cohorts' => new external_multiple_structure(
 423                  new external_single_structure(array(
 424                      'id' => new external_value(PARAM_INT, 'ID of the cohort'),
 425                      'name' => new external_value(PARAM_RAW, 'cohort name'),
 426                      'idnumber' => new external_value(PARAM_RAW, 'cohort idnumber'),
 427                      'description' => new external_value(PARAM_RAW, 'cohort description'),
 428                      'descriptionformat' => new external_format_value('description'),
 429                      'visible' => new external_value(PARAM_BOOL, 'cohort visible'),
 430                      'theme' => new external_value(PARAM_THEME, 'cohort theme', VALUE_OPTIONAL),
 431                  ))
 432              )
 433          ));
 434      }
 435  
 436  
 437  
 438      /**
 439       * Returns description of method parameters
 440       *
 441       * @return external_function_parameters
 442       * @since Moodle 2.5
 443       */
 444      public static function update_cohorts_parameters() {
 445          return new external_function_parameters(
 446              array(
 447                  'cohorts' => new external_multiple_structure(
 448                      new external_single_structure(
 449                          array(
 450                              'id' => new external_value(PARAM_INT, 'ID of the cohort'),
 451                              'categorytype' => new external_single_structure(
 452                                  array(
 453                                      'type' => new external_value(PARAM_TEXT, 'the name of the field: id (numeric value
 454                                          of course category id) or idnumber (alphanumeric value of idnumber course category)
 455                                          or system (value ignored)'),
 456                                      'value' => new external_value(PARAM_RAW, 'the value of the categorytype')
 457                                  )
 458                              ),
 459                              'name' => new external_value(PARAM_RAW, 'cohort name'),
 460                              'idnumber' => new external_value(PARAM_RAW, 'cohort idnumber'),
 461                              'description' => new external_value(PARAM_RAW, 'cohort description', VALUE_OPTIONAL),
 462                              'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
 463                              'visible' => new external_value(PARAM_BOOL, 'cohort visible', VALUE_OPTIONAL),
 464                              'theme' => new external_value(PARAM_THEME,
 465                                  'the cohort theme. The allowcohortthemes setting must be enabled on Moodle',
 466                                  VALUE_OPTIONAL
 467                              ),
 468                          )
 469                      )
 470                  )
 471              )
 472          );
 473      }
 474  
 475      /**
 476       * Update cohorts
 477       *
 478       * @param array $cohorts
 479       * @return null
 480       * @since Moodle 2.5
 481       */
 482      public static function update_cohorts($cohorts) {
 483          global $CFG, $DB;
 484          require_once("$CFG->dirroot/cohort/lib.php");
 485  
 486          $params = self::validate_parameters(self::update_cohorts_parameters(), array('cohorts' => $cohorts));
 487  
 488          $availablethemes = cohort_get_list_of_themes();
 489  
 490          $transaction = $DB->start_delegated_transaction();
 491          $syscontext = context_system::instance();
 492  
 493          foreach ($params['cohorts'] as $cohort) {
 494              $cohort = (object) $cohort;
 495  
 496              if (trim($cohort->name) == '') {
 497                  throw new invalid_parameter_exception('Invalid cohort name');
 498              }
 499  
 500              $oldcohort = $DB->get_record('cohort', array('id' => $cohort->id), '*', MUST_EXIST);
 501              $oldcontext = context::instance_by_id($oldcohort->contextid, MUST_EXIST);
 502              require_capability('moodle/cohort:manage', $oldcontext);
 503  
 504              // Category type (context id).
 505              $categorytype = $cohort->categorytype;
 506              if (!in_array($categorytype['type'], array('idnumber', 'id', 'system'))) {
 507                  throw new invalid_parameter_exception('category type must be id, idnumber or system:' . $categorytype['type']);
 508              }
 509              if ($categorytype['type'] === 'system') {
 510                  $cohort->contextid = $syscontext->id;
 511              } else if ($catid = $DB->get_field('course_categories', 'id', array($categorytype['type'] => $categorytype['value']))) {
 512                  $cohort->contextid = $DB->get_field('context', 'id', array('instanceid' => $catid,
 513                      'contextlevel' => CONTEXT_COURSECAT));
 514              } else {
 515                  throw new invalid_parameter_exception('category not exists: category='.$categorytype['value']);
 516              }
 517  
 518              if ($cohort->contextid != $oldcohort->contextid) {
 519                  $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
 520                  if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
 521                      throw new invalid_parameter_exception('Invalid context');
 522                  }
 523  
 524                  self::validate_context($context);
 525                  require_capability('moodle/cohort:manage', $context);
 526              }
 527  
 528              // Make sure theme is valid.
 529              if (!empty($cohort->theme) && !empty($CFG->allowcohortthemes)) {
 530                  if (empty($availablethemes[$cohort->theme])) {
 531                      $debuginfo = 'The following cohort theme is not installed on this site: '.$cohort->theme;
 532                      throw new moodle_exception('errorinvalidparam', 'webservice', '', 'theme', $debuginfo);
 533                  }
 534              }
 535  
 536              if (!empty($cohort->description)) {
 537                  $cohort->descriptionformat = external_validate_format($cohort->descriptionformat);
 538              }
 539  
 540              cohort_update_cohort($cohort);
 541          }
 542  
 543          $transaction->allow_commit();
 544  
 545          return null;
 546      }
 547  
 548      /**
 549       * Returns description of method result value
 550       *
 551       * @return null
 552       * @since Moodle 2.5
 553       */
 554      public static function update_cohorts_returns() {
 555          return null;
 556      }
 557  
 558      /**
 559       * Returns description of method parameters
 560       *
 561       * @return external_function_parameters
 562       * @since Moodle 2.5
 563       */
 564      public static function add_cohort_members_parameters() {
 565          return new external_function_parameters (
 566              array(
 567                  'members' => new external_multiple_structure (
 568                      new external_single_structure (
 569                          array (
 570                              'cohorttype' => new external_single_structure (
 571                                  array(
 572                                      'type' => new external_value(PARAM_ALPHANUMEXT, 'The name of the field: id
 573                                          (numeric value of cohortid) or idnumber (alphanumeric value of idnumber) '),
 574                                      'value' => new external_value(PARAM_RAW, 'The value of the cohort')
 575                                  )
 576                              ),
 577                              'usertype' => new external_single_structure (
 578                                  array(
 579                                      'type' => new external_value(PARAM_ALPHANUMEXT, 'The name of the field: id
 580                                          (numeric value of id) or username (alphanumeric value of username) '),
 581                                      'value' => new external_value(PARAM_RAW, 'The value of the cohort')
 582                                  )
 583                              )
 584                          )
 585                      )
 586                  )
 587              )
 588          );
 589      }
 590  
 591      /**
 592       * Add cohort members
 593       *
 594       * @param array $members of arrays with keys userid, cohortid
 595       * @since Moodle 2.5
 596       */
 597      public static function add_cohort_members($members) {
 598          global $CFG, $DB;
 599          require_once($CFG->dirroot."/cohort/lib.php");
 600  
 601          $params = self::validate_parameters(self::add_cohort_members_parameters(), array('members' => $members));
 602  
 603          $transaction = $DB->start_delegated_transaction();
 604          $warnings = array();
 605          foreach ($params['members'] as $member) {
 606              // Cohort parameters.
 607              $cohorttype = $member['cohorttype'];
 608              $cohortparam = array($cohorttype['type'] => $cohorttype['value']);
 609              // User parameters.
 610              $usertype = $member['usertype'];
 611              $userparam = array($usertype['type'] => $usertype['value']);
 612              try {
 613                  // Check parameters.
 614                  if ($cohorttype['type'] != 'id' && $cohorttype['type'] != 'idnumber') {
 615                      $warning = array();
 616                      $warning['warningcode'] = '1';
 617                      $warning['message'] = 'invalid parameter: cohortype='.$cohorttype['type'];
 618                      $warnings[] = $warning;
 619                      continue;
 620                  }
 621                  if ($usertype['type'] != 'id' && $usertype['type'] != 'username') {
 622                      $warning = array();
 623                      $warning['warningcode'] = '1';
 624                      $warning['message'] = 'invalid parameter: usertype='.$usertype['type'];
 625                      $warnings[] = $warning;
 626                      continue;
 627                  }
 628                  // Extract parameters.
 629                  if (!$cohortid = $DB->get_field('cohort', 'id', $cohortparam)) {
 630                      $warning = array();
 631                      $warning['warningcode'] = '2';
 632                      $warning['message'] = 'cohort '.$cohorttype['type'].'='.$cohorttype['value'].' not exists';
 633                      $warnings[] = $warning;
 634                      continue;
 635                  }
 636                  if (!$userid = $DB->get_field('user', 'id', array_merge($userparam, array('deleted' => 0,
 637                      'mnethostid' => $CFG->mnet_localhost_id)))) {
 638                      $warning = array();
 639                      $warning['warningcode'] = '2';
 640                      $warning['message'] = 'user '.$usertype['type'].'='.$usertype['value'].' not exists';
 641                      $warnings[] = $warning;
 642                      continue;
 643                  }
 644                  if ($DB->record_exists('cohort_members', array('cohortid' => $cohortid, 'userid' => $userid))) {
 645                      $warning = array();
 646                      $warning['warningcode'] = '3';
 647                      $warning['message'] = 'record already exists: cohort('.$cohorttype['type'].'='.$cohorttype['value'].' '.
 648                          $usertype['type'].'='.$usertype['value'].')';
 649                      $warnings[] = $warning;
 650                      continue;
 651                  }
 652                  $cohort = $DB->get_record('cohort', array('id'=>$cohortid), '*', MUST_EXIST);
 653                  $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
 654                  if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
 655                      $warning = array();
 656                      $warning['warningcode'] = '1';
 657                      $warning['message'] = 'Invalid context: '.$context->contextlevel;
 658                      $warnings[] = $warning;
 659                      continue;
 660                  }
 661                  self::validate_context($context);
 662              } catch (Exception $e) {
 663                  throw new moodle_exception('Error', 'cohort', '', $e->getMessage());
 664              }
 665              if (!has_any_capability(array('moodle/cohort:manage', 'moodle/cohort:assign'), $context)) {
 666                  throw new required_capability_exception($context, 'moodle/cohort:assign', 'nopermissions', '');
 667              }
 668              cohort_add_member($cohortid, $userid);
 669          }
 670          $transaction->allow_commit();
 671          // Return.
 672          $result = array();
 673          $result['warnings'] = $warnings;
 674          return $result;
 675      }
 676  
 677      /**
 678       * Returns description of method result value
 679       *
 680       * @return null
 681       * @since Moodle 2.5
 682       */
 683      public static function add_cohort_members_returns() {
 684          return new external_single_structure(
 685              array(
 686                  'warnings' => new external_warnings()
 687              )
 688          );
 689      }
 690  
 691      /**
 692       * Returns description of method parameters
 693       *
 694       * @return external_function_parameters
 695       * @since Moodle 2.5
 696       */
 697      public static function delete_cohort_members_parameters() {
 698          return new external_function_parameters(
 699              array(
 700                  'members' => new external_multiple_structure(
 701                      new external_single_structure(
 702                          array(
 703                              'cohortid' => new external_value(PARAM_INT, 'cohort record id'),
 704                              'userid' => new external_value(PARAM_INT, 'user id'),
 705                          )
 706                      )
 707                  )
 708              )
 709          );
 710      }
 711  
 712      /**
 713       * Delete cohort members
 714       *
 715       * @param array $members of arrays with keys userid, cohortid
 716       * @since Moodle 2.5
 717       */
 718      public static function delete_cohort_members($members) {
 719          global $CFG, $DB;
 720          require_once("$CFG->dirroot/cohort/lib.php");
 721  
 722          // Validate parameters.
 723          $params = self::validate_parameters(self::delete_cohort_members_parameters(), array('members' => $members));
 724  
 725          $transaction = $DB->start_delegated_transaction();
 726  
 727          foreach ($params['members'] as $member) {
 728              $cohortid = $member['cohortid'];
 729              $userid = $member['userid'];
 730  
 731              $cohort = $DB->get_record('cohort', array('id' => $cohortid), '*', MUST_EXIST);
 732              $user = $DB->get_record('user', array('id' => $userid, 'deleted' => 0, 'mnethostid' => $CFG->mnet_localhost_id),
 733                  '*', MUST_EXIST);
 734  
 735              // Now security checks.
 736              $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
 737              if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
 738                  throw new invalid_parameter_exception('Invalid context');
 739              }
 740              self::validate_context($context);
 741              if (!has_any_capability(array('moodle/cohort:manage', 'moodle/cohort:assign'), $context)) {
 742                  throw new required_capability_exception($context, 'moodle/cohort:assign', 'nopermissions', '');
 743              }
 744  
 745              cohort_remove_member($cohort->id, $user->id);
 746          }
 747          $transaction->allow_commit();
 748      }
 749  
 750      /**
 751       * Returns description of method result value
 752       *
 753       * @return null
 754       * @since Moodle 2.5
 755       */
 756      public static function delete_cohort_members_returns() {
 757          return null;
 758      }
 759  
 760      /**
 761       * Returns description of method parameters
 762       *
 763       * @return external_function_parameters
 764       * @since Moodle 2.5
 765       */
 766      public static function get_cohort_members_parameters() {
 767          return new external_function_parameters(
 768              array(
 769                  'cohortids' => new external_multiple_structure(new external_value(PARAM_INT, 'Cohort ID')),
 770              )
 771          );
 772      }
 773  
 774      /**
 775       * Return all members for a cohort
 776       *
 777       * @param array $cohortids array of cohort ids
 778       * @return array with cohort id keys containing arrays of user ids
 779       * @since Moodle 2.5
 780       */
 781      public static function get_cohort_members($cohortids) {
 782          global $DB;
 783          $params = self::validate_parameters(self::get_cohort_members_parameters(), array('cohortids' => $cohortids));
 784  
 785          $members = array();
 786  
 787          foreach ($params['cohortids'] as $cohortid) {
 788              // Validate params.
 789              $cohort = $DB->get_record('cohort', array('id' => $cohortid), '*', MUST_EXIST);
 790              // Now security checks.
 791              $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
 792              if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
 793                  throw new invalid_parameter_exception('Invalid context');
 794              }
 795              self::validate_context($context);
 796              if (!has_any_capability(array('moodle/cohort:manage', 'moodle/cohort:view'), $context)) {
 797                  throw new required_capability_exception($context, 'moodle/cohort:view', 'nopermissions', '');
 798              }
 799  
 800              $cohortmembers = $DB->get_records_sql("SELECT u.id FROM {user} u, {cohort_members} cm
 801                  WHERE u.id = cm.userid AND cm.cohortid = ?
 802                  ORDER BY lastname ASC, firstname ASC", array($cohort->id));
 803              $members[] = array('cohortid' => $cohortid, 'userids' => array_keys($cohortmembers));
 804          }
 805          return $members;
 806      }
 807  
 808      /**
 809       * Returns description of method result value
 810       *
 811       * @return external_description
 812       * @since Moodle 2.5
 813       */
 814      public static function get_cohort_members_returns() {
 815          return new external_multiple_structure(
 816              new external_single_structure(
 817                  array(
 818                      'cohortid' => new external_value(PARAM_INT, 'cohort record id'),
 819                      'userids' => new external_multiple_structure(new external_value(PARAM_INT, 'user id')),
 820                  )
 821              )
 822          );
 823      }
 824  }