Merge branch 'MDL-79665' of https://github.com/paulholden/moodle
[moodle.git] / cohort / externallib.php
blob6a31ed39e29f13c1b0953e4ac0b6647edc2da917
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.
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/>.
17 use core_external\external_api;
18 use core_external\external_format_value;
19 use core_external\external_function_parameters;
20 use core_external\external_multiple_structure;
21 use core_external\external_single_structure;
22 use core_external\external_value;
23 use core_external\external_warnings;
24 use core_external\util;
26 defined('MOODLE_INTERNAL') || die();
28 require_once($CFG->dirroot . '/cohort/lib.php');
30 /**
31 * External cohort API
33 * @package core_cohort
34 * @category external
35 * @copyright MediaTouch 2000 srl
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38 class core_cohort_external extends external_api {
40 /**
41 * Returns description of method parameters
43 * @return external_function_parameters
44 * @since Moodle 2.5
46 public static function create_cohorts_parameters() {
47 return new external_function_parameters(
48 array(
49 'cohorts' => new external_multiple_structure(
50 new external_single_structure(
51 array(
52 'categorytype' => new external_single_structure(
53 array(
54 'type' => new external_value(PARAM_TEXT, 'the name of the field: id (numeric value
55 of course category id) or idnumber (alphanumeric value of idnumber course category)
56 or system (value ignored)'),
57 'value' => new external_value(PARAM_RAW, 'the value of the categorytype')
60 'name' => new external_value(PARAM_RAW, 'cohort name'),
61 'idnumber' => new external_value(PARAM_RAW, 'cohort idnumber'),
62 'description' => new external_value(PARAM_RAW, 'cohort description', VALUE_OPTIONAL),
63 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
64 'visible' => new external_value(PARAM_BOOL, 'cohort visible', VALUE_OPTIONAL, true),
65 'theme' => new external_value(PARAM_THEME,
66 'the cohort theme. The allowcohortthemes setting must be enabled on Moodle',
67 VALUE_OPTIONAL
69 'customfields' => self::build_custom_fields_parameters_structure(),
77 /**
78 * Create one or more cohorts
80 * @param array $cohorts An array of cohorts to create.
81 * @return array An array of arrays
82 * @since Moodle 2.5
84 public static function create_cohorts($cohorts) {
85 global $CFG, $DB;
86 require_once("$CFG->dirroot/cohort/lib.php");
88 $params = self::validate_parameters(self::create_cohorts_parameters(), array('cohorts' => $cohorts));
90 $availablethemes = cohort_get_list_of_themes();
92 $transaction = $DB->start_delegated_transaction();
94 $syscontext = context_system::instance();
95 $cohortids = array();
97 foreach ($params['cohorts'] as $cohort) {
98 $cohort = (object)$cohort;
100 // Category type (context id).
101 $categorytype = $cohort->categorytype;
102 if (!in_array($categorytype['type'], array('idnumber', 'id', 'system'))) {
103 throw new invalid_parameter_exception('category type must be id, idnumber or system:' . $categorytype['type']);
105 if ($categorytype['type'] === 'system') {
106 $cohort->contextid = $syscontext->id;
107 } else if ($catid = $DB->get_field('course_categories', 'id', array($categorytype['type'] => $categorytype['value']))) {
108 $catcontext = context_coursecat::instance($catid);
109 $cohort->contextid = $catcontext->id;
110 } else {
111 throw new invalid_parameter_exception('category not exists: category '
112 .$categorytype['type'].' = '.$categorytype['value']);
114 // Make sure that the idnumber doesn't already exist.
115 if ($DB->record_exists('cohort', array('idnumber' => $cohort->idnumber))) {
116 throw new invalid_parameter_exception('record already exists: idnumber='.$cohort->idnumber);
118 $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
119 if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
120 throw new invalid_parameter_exception('Invalid context');
122 self::validate_context($context);
123 require_capability('moodle/cohort:manage', $context);
125 // Make sure theme is valid.
126 if (isset($cohort->theme)) {
127 if (!empty($CFG->allowcohortthemes)) {
128 if (empty($availablethemes[$cohort->theme])) {
129 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'theme');
134 // Validate format.
135 $cohort->descriptionformat = util::validate_format($cohort->descriptionformat);
137 // Custom fields.
138 if (!empty($cohort->customfields)) {
139 foreach ($cohort->customfields as $field) {
140 $fieldname = self::build_custom_field_name($field['shortname']);
141 $cohort->{$fieldname} = $field['value'];
143 unset($cohort->customfields);
146 $cohort->id = cohort_add_cohort($cohort);
148 list($cohort->description, $cohort->descriptionformat) =
149 \core_external\util::format_text($cohort->description, $cohort->descriptionformat,
150 $context, 'cohort', 'description', $cohort->id);
151 $cohortids[] = (array)$cohort;
153 $transaction->allow_commit();
155 return $cohortids;
159 * Returns description of method result value
161 * @return \core_external\external_description
162 * @since Moodle 2.5
164 public static function create_cohorts_returns() {
165 return new external_multiple_structure(
166 new external_single_structure(
167 array(
168 'id' => new external_value(PARAM_INT, 'cohort id'),
169 'name' => new external_value(PARAM_RAW, 'cohort name'),
170 'idnumber' => new external_value(PARAM_RAW, 'cohort idnumber'),
171 'description' => new external_value(PARAM_RAW, 'cohort description'),
172 'descriptionformat' => new external_format_value('description'),
173 'visible' => new external_value(PARAM_BOOL, 'cohort visible'),
174 'theme' => new external_value(PARAM_THEME, 'cohort theme', VALUE_OPTIONAL),
181 * Returns description of method parameters
183 * @return external_function_parameters
184 * @since Moodle 2.5
186 public static function delete_cohorts_parameters() {
187 return new external_function_parameters(
188 array(
189 'cohortids' => new external_multiple_structure(new external_value(PARAM_INT, 'cohort ID')),
195 * Delete cohorts
197 * @param array $cohortids
198 * @return null
199 * @since Moodle 2.5
201 public static function delete_cohorts($cohortids) {
202 global $CFG, $DB;
203 require_once("$CFG->dirroot/cohort/lib.php");
205 $params = self::validate_parameters(self::delete_cohorts_parameters(), array('cohortids' => $cohortids));
207 $transaction = $DB->start_delegated_transaction();
209 foreach ($params['cohortids'] as $cohortid) {
210 // Validate params.
211 $cohortid = validate_param($cohortid, PARAM_INT);
212 $cohort = $DB->get_record('cohort', array('id' => $cohortid), '*', MUST_EXIST);
214 // Now security checks.
215 $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
216 if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
217 throw new invalid_parameter_exception('Invalid context');
219 self::validate_context($context);
220 require_capability('moodle/cohort:manage', $context);
221 cohort_delete_cohort($cohort);
223 $transaction->allow_commit();
225 return null;
229 * Returns description of method result value
231 * @return null
232 * @since Moodle 2.5
234 public static function delete_cohorts_returns() {
235 return null;
239 * Returns description of method parameters
241 * @return external_function_parameters
242 * @since Moodle 2.5
244 public static function get_cohorts_parameters() {
245 return new external_function_parameters(
246 array(
247 'cohortids' => new external_multiple_structure(new external_value(PARAM_INT, 'Cohort ID')
248 , 'List of cohort id. A cohort id is an integer.', VALUE_DEFAULT, array()),
254 * Get cohorts definition specified by ids
256 * @param array $cohortids array of cohort ids
257 * @return array of cohort objects (id, courseid, name)
258 * @since Moodle 2.5
260 public static function get_cohorts($cohortids = array()) {
261 global $DB, $CFG;
263 $params = self::validate_parameters(self::get_cohorts_parameters(), array('cohortids' => $cohortids));
265 if (empty($cohortids)) {
266 $cohorts = $DB->get_records('cohort');
267 if (!empty($cohorts)) {
268 $cohortids = array_keys($cohorts);
270 } else {
271 $cohorts = $DB->get_records_list('cohort', 'id', $params['cohortids']);
274 $customfieldsdata = self::get_custom_fields_data($cohortids);
275 $cohortsinfo = array();
276 foreach ($cohorts as $cohort) {
277 // Now security checks.
278 $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
279 if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
280 throw new invalid_parameter_exception('Invalid context');
282 self::validate_context($context);
283 if (!has_any_capability(array('moodle/cohort:manage', 'moodle/cohort:view'), $context)) {
284 throw new required_capability_exception($context, 'moodle/cohort:view', 'nopermissions', '');
287 // Only return theme when $CFG->allowcohortthemes is enabled.
288 if (!empty($cohort->theme) && empty($CFG->allowcohortthemes)) {
289 $cohort->theme = null;
292 list($cohort->description, $cohort->descriptionformat) =
293 \core_external\util::format_text($cohort->description, $cohort->descriptionformat,
294 $context, 'cohort', 'description', $cohort->id);
296 $cohort->customfields = !empty($customfieldsdata[$cohort->id]) ? $customfieldsdata[$cohort->id] : [];
297 $cohortsinfo[] = (array) $cohort;
299 return $cohortsinfo;
304 * Returns description of method result value
306 * @return \core_external\external_description
307 * @since Moodle 2.5
309 public static function get_cohorts_returns() {
310 return new external_multiple_structure(
311 new external_single_structure(
312 array(
313 'id' => new external_value(PARAM_INT, 'ID of the cohort'),
314 'name' => new external_value(PARAM_RAW, 'cohort name'),
315 'idnumber' => new external_value(PARAM_RAW, 'cohort idnumber'),
316 'description' => new external_value(PARAM_RAW, 'cohort description'),
317 'descriptionformat' => new external_format_value('description'),
318 'visible' => new external_value(PARAM_BOOL, 'cohort visible'),
319 'theme' => new external_value(PARAM_THEME, 'cohort theme', VALUE_OPTIONAL),
320 'customfields' => self::build_custom_fields_returns_structure(),
327 * Returns the description of external function parameters.
329 * @return external_function_parameters
331 public static function search_cohorts_parameters() {
332 $query = new external_value(
333 PARAM_RAW,
334 'Query string'
336 $includes = new external_value(
337 PARAM_ALPHA,
338 'What other contexts to fetch the frameworks from. (all, parents, self)',
339 VALUE_DEFAULT,
340 'parents'
342 $limitfrom = new external_value(
343 PARAM_INT,
344 'limitfrom we are fetching the records from',
345 VALUE_DEFAULT,
348 $limitnum = new external_value(
349 PARAM_INT,
350 'Number of records to fetch',
351 VALUE_DEFAULT,
354 return new external_function_parameters(array(
355 'query' => $query,
356 'context' => self::get_context_parameters(),
357 'includes' => $includes,
358 'limitfrom' => $limitfrom,
359 'limitnum' => $limitnum
364 * Search cohorts.
366 * @param string $query
367 * @param array $context
368 * @param string $includes
369 * @param int $limitfrom
370 * @param int $limitnum
371 * @return array
373 public static function search_cohorts($query, $context, $includes = 'parents', $limitfrom = 0, $limitnum = 25) {
374 global $CFG;
375 require_once($CFG->dirroot . '/cohort/lib.php');
377 $params = self::validate_parameters(self::search_cohorts_parameters(), array(
378 'query' => $query,
379 'context' => $context,
380 'includes' => $includes,
381 'limitfrom' => $limitfrom,
382 'limitnum' => $limitnum,
384 $query = $params['query'];
385 $includes = $params['includes'];
386 $context = self::get_context_from_params($params['context']);
387 $limitfrom = $params['limitfrom'];
388 $limitnum = $params['limitnum'];
390 self::validate_context($context);
392 $manager = has_capability('moodle/cohort:manage', $context);
393 if (!$manager) {
394 require_capability('moodle/cohort:view', $context);
397 // TODO Make this more efficient.
398 if ($includes == 'self') {
399 $results = cohort_get_cohorts($context->id, $limitfrom, $limitnum, $query);
400 $results = $results['cohorts'];
401 } else if ($includes == 'parents') {
402 $results = cohort_get_cohorts($context->id, $limitfrom, $limitnum, $query);
403 $results = $results['cohorts'];
404 if (!$context instanceof context_system) {
405 $results = array_merge($results, cohort_get_available_cohorts($context, COHORT_ALL, $limitfrom, $limitnum, $query));
407 } else if ($includes == 'all') {
408 $results = cohort_get_all_cohorts($limitfrom, $limitnum, $query);
409 $results = $results['cohorts'];
410 } else {
411 throw new coding_exception('Invalid parameter value for \'includes\'.');
414 $cohorts = array();
416 if (!empty($results)) {
417 $cohortids = array_keys($results);
418 $customfieldsdata = self::get_custom_fields_data($cohortids);
421 foreach ($results as $key => $cohort) {
422 $cohortcontext = context::instance_by_id($cohort->contextid);
424 // Only return theme when $CFG->allowcohortthemes is enabled.
425 if (!empty($cohort->theme) && empty($CFG->allowcohortthemes)) {
426 $cohort->theme = null;
429 if (!isset($cohort->description)) {
430 $cohort->description = '';
432 if (!isset($cohort->descriptionformat)) {
433 $cohort->descriptionformat = FORMAT_PLAIN;
436 list($cohort->description, $cohort->descriptionformat) =
437 \core_external\util::format_text($cohort->description, $cohort->descriptionformat,
438 $cohortcontext, 'cohort', 'description', $cohort->id);
440 $cohort->customfields = !empty($customfieldsdata[$cohort->id]) ? $customfieldsdata[$cohort->id] : [];
442 $cohorts[$key] = $cohort;
445 return array('cohorts' => $cohorts);
449 * Returns description of external function result value.
451 * @return \core_external\external_description
453 public static function search_cohorts_returns() {
454 return new external_single_structure(array(
455 'cohorts' => new external_multiple_structure(
456 new external_single_structure(array(
457 'id' => new external_value(PARAM_INT, 'ID of the cohort'),
458 'name' => new external_value(PARAM_RAW, 'cohort name'),
459 'idnumber' => new external_value(PARAM_RAW, 'cohort idnumber'),
460 'description' => new external_value(PARAM_RAW, 'cohort description'),
461 'descriptionformat' => new external_format_value('description'),
462 'visible' => new external_value(PARAM_BOOL, 'cohort visible'),
463 'theme' => new external_value(PARAM_THEME, 'cohort theme', VALUE_OPTIONAL),
464 'customfields' => self::build_custom_fields_returns_structure(),
473 * Returns description of method parameters
475 * @return external_function_parameters
476 * @since Moodle 2.5
478 public static function update_cohorts_parameters() {
479 return new external_function_parameters(
480 array(
481 'cohorts' => new external_multiple_structure(
482 new external_single_structure(
483 array(
484 'id' => new external_value(PARAM_INT, 'ID of the cohort'),
485 'categorytype' => new external_single_structure(
486 array(
487 'type' => new external_value(PARAM_TEXT, 'the name of the field: id (numeric value
488 of course category id) or idnumber (alphanumeric value of idnumber course category)
489 or system (value ignored)'),
490 'value' => new external_value(PARAM_RAW, 'the value of the categorytype')
493 'name' => new external_value(PARAM_RAW, 'cohort name'),
494 'idnumber' => new external_value(PARAM_RAW, 'cohort idnumber'),
495 'description' => new external_value(PARAM_RAW, 'cohort description', VALUE_OPTIONAL),
496 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
497 'visible' => new external_value(PARAM_BOOL, 'cohort visible', VALUE_OPTIONAL),
498 'theme' => new external_value(PARAM_THEME,
499 'the cohort theme. The allowcohortthemes setting must be enabled on Moodle',
500 VALUE_OPTIONAL
502 'customfields' => self::build_custom_fields_parameters_structure(),
511 * Update cohorts
513 * @param array $cohorts
514 * @return null
515 * @since Moodle 2.5
517 public static function update_cohorts($cohorts) {
518 global $CFG, $DB;
519 require_once("$CFG->dirroot/cohort/lib.php");
521 $params = self::validate_parameters(self::update_cohorts_parameters(), array('cohorts' => $cohorts));
523 $availablethemes = cohort_get_list_of_themes();
525 $transaction = $DB->start_delegated_transaction();
526 $syscontext = context_system::instance();
528 foreach ($params['cohorts'] as $cohort) {
529 $cohort = (object) $cohort;
531 if (trim($cohort->name) == '') {
532 throw new invalid_parameter_exception('Invalid cohort name');
535 $oldcohort = $DB->get_record('cohort', array('id' => $cohort->id), '*', MUST_EXIST);
536 $oldcontext = context::instance_by_id($oldcohort->contextid, MUST_EXIST);
537 require_capability('moodle/cohort:manage', $oldcontext);
539 // Category type (context id).
540 $categorytype = $cohort->categorytype;
541 if (!in_array($categorytype['type'], array('idnumber', 'id', 'system'))) {
542 throw new invalid_parameter_exception('category type must be id, idnumber or system:' . $categorytype['type']);
544 if ($categorytype['type'] === 'system') {
545 $cohort->contextid = $syscontext->id;
546 } else if ($catid = $DB->get_field('course_categories', 'id', array($categorytype['type'] => $categorytype['value']))) {
547 $cohort->contextid = $DB->get_field('context', 'id', array('instanceid' => $catid,
548 'contextlevel' => CONTEXT_COURSECAT));
549 } else {
550 throw new invalid_parameter_exception('category not exists: category='.$categorytype['value']);
553 if ($cohort->contextid != $oldcohort->contextid) {
554 $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
555 if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
556 throw new invalid_parameter_exception('Invalid context');
559 self::validate_context($context);
560 require_capability('moodle/cohort:manage', $context);
563 // Make sure theme is valid.
564 if (!empty($cohort->theme) && !empty($CFG->allowcohortthemes)) {
565 if (empty($availablethemes[$cohort->theme])) {
566 $debuginfo = 'The following cohort theme is not installed on this site: '.$cohort->theme;
567 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'theme', $debuginfo);
571 if (!empty($cohort->description)) {
572 $cohort->descriptionformat = util::validate_format($cohort->descriptionformat);
575 // Custom fields.
576 if (!empty($cohort->customfields)) {
577 foreach ($cohort->customfields as $field) {
578 $fieldname = self::build_custom_field_name($field['shortname']);
579 $cohort->{$fieldname} = $field['value'];
581 unset($cohort->customfields);
584 cohort_update_cohort($cohort);
587 $transaction->allow_commit();
589 return null;
593 * Returns description of method result value
595 * @return null
596 * @since Moodle 2.5
598 public static function update_cohorts_returns() {
599 return null;
603 * Returns description of method parameters
605 * @return external_function_parameters
606 * @since Moodle 2.5
608 public static function add_cohort_members_parameters() {
609 return new external_function_parameters (
610 array(
611 'members' => new external_multiple_structure (
612 new external_single_structure (
613 array (
614 'cohorttype' => new external_single_structure (
615 array(
616 'type' => new external_value(PARAM_ALPHANUMEXT, 'The name of the field: id
617 (numeric value of cohortid) or idnumber (alphanumeric value of idnumber) '),
618 'value' => new external_value(PARAM_RAW, 'The value of the cohort')
621 'usertype' => new external_single_structure (
622 array(
623 'type' => new external_value(PARAM_ALPHANUMEXT, 'The name of the field: id
624 (numeric value of id) or username (alphanumeric value of username) '),
625 'value' => new external_value(PARAM_RAW, 'The value of the cohort')
636 * Add cohort members
638 * @param array $members of arrays with keys userid, cohortid
639 * @since Moodle 2.5
641 public static function add_cohort_members($members) {
642 global $CFG, $DB;
643 require_once($CFG->dirroot."/cohort/lib.php");
645 $params = self::validate_parameters(self::add_cohort_members_parameters(), array('members' => $members));
647 $transaction = $DB->start_delegated_transaction();
648 $warnings = array();
649 foreach ($params['members'] as $member) {
650 // Cohort parameters.
651 $cohorttype = $member['cohorttype'];
652 $cohortparam = array($cohorttype['type'] => $cohorttype['value']);
653 // User parameters.
654 $usertype = $member['usertype'];
655 $userparam = array($usertype['type'] => $usertype['value']);
656 try {
657 // Check parameters.
658 if ($cohorttype['type'] != 'id' && $cohorttype['type'] != 'idnumber') {
659 $warning = array();
660 $warning['warningcode'] = '1';
661 $warning['message'] = 'invalid parameter: cohortype='.$cohorttype['type'];
662 $warnings[] = $warning;
663 continue;
665 if ($usertype['type'] != 'id' && $usertype['type'] != 'username') {
666 $warning = array();
667 $warning['warningcode'] = '1';
668 $warning['message'] = 'invalid parameter: usertype='.$usertype['type'];
669 $warnings[] = $warning;
670 continue;
672 // Extract parameters.
673 if (!$cohortid = $DB->get_field('cohort', 'id', $cohortparam)) {
674 $warning = array();
675 $warning['warningcode'] = '2';
676 $warning['message'] = 'cohort '.$cohorttype['type'].'='.$cohorttype['value'].' not exists';
677 $warnings[] = $warning;
678 continue;
680 if (!$userid = $DB->get_field('user', 'id', array_merge($userparam, array('deleted' => 0,
681 'mnethostid' => $CFG->mnet_localhost_id)))) {
682 $warning = array();
683 $warning['warningcode'] = '2';
684 $warning['message'] = 'user '.$usertype['type'].'='.$usertype['value'].' not exists';
685 $warnings[] = $warning;
686 continue;
688 if ($DB->record_exists('cohort_members', array('cohortid' => $cohortid, 'userid' => $userid))) {
689 $warning = array();
690 $warning['warningcode'] = '3';
691 $warning['message'] = 'record already exists: cohort('.$cohorttype['type'].'='.$cohorttype['value'].' '.
692 $usertype['type'].'='.$usertype['value'].')';
693 $warnings[] = $warning;
694 continue;
696 $cohort = $DB->get_record('cohort', array('id'=>$cohortid), '*', MUST_EXIST);
697 $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
698 if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
699 $warning = array();
700 $warning['warningcode'] = '1';
701 $warning['message'] = 'Invalid context: '.$context->contextlevel;
702 $warnings[] = $warning;
703 continue;
705 self::validate_context($context);
706 } catch (Exception $e) {
707 throw new moodle_exception('Error', 'cohort', '', $e->getMessage());
709 if (!has_any_capability(array('moodle/cohort:manage', 'moodle/cohort:assign'), $context)) {
710 throw new required_capability_exception($context, 'moodle/cohort:assign', 'nopermissions', '');
712 cohort_add_member($cohortid, $userid);
714 $transaction->allow_commit();
715 // Return.
716 $result = array();
717 $result['warnings'] = $warnings;
718 return $result;
722 * Returns description of method result value
724 * @return null
725 * @since Moodle 2.5
727 public static function add_cohort_members_returns() {
728 return new external_single_structure(
729 array(
730 'warnings' => new external_warnings()
736 * Returns description of method parameters
738 * @return external_function_parameters
739 * @since Moodle 2.5
741 public static function delete_cohort_members_parameters() {
742 return new external_function_parameters(
743 array(
744 'members' => new external_multiple_structure(
745 new external_single_structure(
746 array(
747 'cohortid' => new external_value(PARAM_INT, 'cohort record id'),
748 'userid' => new external_value(PARAM_INT, 'user id'),
757 * Delete cohort members
759 * @param array $members of arrays with keys userid, cohortid
760 * @since Moodle 2.5
762 public static function delete_cohort_members($members) {
763 global $CFG, $DB;
764 require_once("$CFG->dirroot/cohort/lib.php");
766 // Validate parameters.
767 $params = self::validate_parameters(self::delete_cohort_members_parameters(), array('members' => $members));
769 $transaction = $DB->start_delegated_transaction();
771 foreach ($params['members'] as $member) {
772 $cohortid = $member['cohortid'];
773 $userid = $member['userid'];
775 $cohort = $DB->get_record('cohort', array('id' => $cohortid), '*', MUST_EXIST);
776 $user = $DB->get_record('user', array('id' => $userid, 'deleted' => 0, 'mnethostid' => $CFG->mnet_localhost_id),
777 '*', MUST_EXIST);
779 // Now security checks.
780 $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
781 if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
782 throw new invalid_parameter_exception('Invalid context');
784 self::validate_context($context);
785 if (!has_any_capability(array('moodle/cohort:manage', 'moodle/cohort:assign'), $context)) {
786 throw new required_capability_exception($context, 'moodle/cohort:assign', 'nopermissions', '');
789 cohort_remove_member($cohort->id, $user->id);
791 $transaction->allow_commit();
795 * Returns description of method result value
797 * @return null
798 * @since Moodle 2.5
800 public static function delete_cohort_members_returns() {
801 return null;
805 * Returns description of method parameters
807 * @return external_function_parameters
808 * @since Moodle 2.5
810 public static function get_cohort_members_parameters() {
811 return new external_function_parameters(
812 array(
813 'cohortids' => new external_multiple_structure(new external_value(PARAM_INT, 'Cohort ID')),
819 * Return all members for a cohort
821 * @param array $cohortids array of cohort ids
822 * @return array with cohort id keys containing arrays of user ids
823 * @since Moodle 2.5
825 public static function get_cohort_members($cohortids) {
826 global $DB;
827 $params = self::validate_parameters(self::get_cohort_members_parameters(), array('cohortids' => $cohortids));
829 $members = array();
831 foreach ($params['cohortids'] as $cohortid) {
832 // Validate params.
833 $cohort = $DB->get_record('cohort', array('id' => $cohortid), '*', MUST_EXIST);
834 // Now security checks.
835 $context = context::instance_by_id($cohort->contextid, MUST_EXIST);
836 if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
837 throw new invalid_parameter_exception('Invalid context');
839 self::validate_context($context);
840 if (!has_any_capability(array('moodle/cohort:manage', 'moodle/cohort:view'), $context)) {
841 throw new required_capability_exception($context, 'moodle/cohort:view', 'nopermissions', '');
844 $cohortmembers = $DB->get_records_sql("SELECT u.id FROM {user} u, {cohort_members} cm
845 WHERE u.id = cm.userid AND cm.cohortid = ?
846 ORDER BY lastname ASC, firstname ASC", array($cohort->id));
847 $members[] = array('cohortid' => $cohortid, 'userids' => array_keys($cohortmembers));
849 return $members;
853 * Returns description of method result value
855 * @return \core_external\external_description
856 * @since Moodle 2.5
858 public static function get_cohort_members_returns() {
859 return new external_multiple_structure(
860 new external_single_structure(
861 array(
862 'cohortid' => new external_value(PARAM_INT, 'cohort record id'),
863 'userids' => new external_multiple_structure(new external_value(PARAM_INT, 'user id')),
870 * Builds a structure for custom fields parameters.
872 * @return \core_external\external_multiple_structure
874 protected static function build_custom_fields_parameters_structure(): external_multiple_structure {
875 return new external_multiple_structure(
876 new external_single_structure(
877 array(
878 'shortname' => new external_value(PARAM_ALPHANUMEXT, 'The shortname of the custom field'),
879 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
881 ), 'Custom fields for the cohort', VALUE_OPTIONAL
886 * Builds a structure for custom fields returns.
888 * @return \core_external\external_multiple_structure
890 protected static function build_custom_fields_returns_structure(): external_multiple_structure {
891 return new external_multiple_structure(
892 new external_single_structure(
893 array(
894 'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
895 'shortname' => new external_value(PARAM_RAW,
896 'The shortname of the custom field - to be able to build the field class in the code'),
897 'type' => new external_value(PARAM_ALPHANUMEXT,
898 'The type of the custom field - text field, checkbox...'),
899 'valueraw' => new external_value(PARAM_RAW, 'The raw value of the custom field'),
900 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
902 ), 'Custom fields', VALUE_OPTIONAL
907 * Returns custom fields data for provided cohorts.
909 * @param array $cohortids a list of cohort IDs to provide data for.
910 * @return array
912 protected static function get_custom_fields_data(array $cohortids): array {
913 $result = [];
915 $customfieldsdata = cohort_get_custom_fields_data($cohortids);
917 foreach ($customfieldsdata as $cohortid => $fieldcontrollers) {
918 foreach ($fieldcontrollers as $fieldcontroller) {
919 $result[$cohortid][] = [
920 'type' => $fieldcontroller->get_field()->get('type'),
921 'value' => $fieldcontroller->export_value(),
922 'valueraw' => $fieldcontroller->get_value(),
923 'name' => $fieldcontroller->get_field()->get('name'),
924 'shortname' => $fieldcontroller->get_field()->get('shortname'),
929 return $result;
933 * Builds a suitable name of a custom field for a custom field handler based on provided shortname.
935 * @param string $shortname shortname to use.
936 * @return string
938 protected static function build_custom_field_name(string $shortname): string {
939 return 'customfield_' . $shortname;