2 // This file is part of Moodle - http://moodle.org/
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.
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
;
25 use core_group\visibility
;
27 defined('MOODLE_INTERNAL') ||
die();
29 require_once($CFG->dirroot
. '/group/lib.php');
32 * Group external functions
36 * @copyright 2011 Jerome Mouneyrac
37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 class core_group_external
extends external_api
{
44 * Validate visibility.
46 * @param int $visibility Visibility string, must one of the visibility class constants.
47 * @throws invalid_parameter_exception if visibility is not an allowed value.
49 protected static function validate_visibility(int $visibility): void
{
51 GROUPS_VISIBILITY_ALL
,
52 GROUPS_VISIBILITY_MEMBERS
,
53 GROUPS_VISIBILITY_OWN
,
54 GROUPS_VISIBILITY_NONE
,
56 if (!array_key_exists($visibility, $allowed)) {
57 throw new invalid_parameter_exception('Invalid group visibility provided. Must be one of '
58 . join(',', $allowed));
63 * Returns description of method parameters
65 * @return external_function_parameters
68 public static function create_groups_parameters() {
69 return new external_function_parameters(
71 'groups' => new external_multiple_structure(
72 new external_single_structure(
74 'courseid' => new external_value(PARAM_INT
, 'id of course'),
75 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
76 'description' => new external_value(PARAM_RAW
, 'group description text'),
77 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT
),
78 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase', VALUE_OPTIONAL
),
79 'idnumber' => new external_value(PARAM_RAW
, 'id number', VALUE_OPTIONAL
),
80 'visibility' => new external_value(PARAM_INT
,
81 'group visibility mode. 0 = Visible to all. 1 = Visible to members. '
82 . '2 = See own membership. 3 = Membership is hidden. default: 0',
84 'participation' => new external_value(PARAM_BOOL
,
85 'activity participation enabled? Only for "all" and "members" visibility. Default true.',
87 'customfields' => self
::build_custom_fields_parameters_structure(),
89 ), 'List of group object. A group has a courseid, a name, a description and an enrolment key.'
98 * @param array $groups array of group description arrays (with keys groupname and courseid)
99 * @return array of newly created groups
102 public static function create_groups($groups) {
104 require_once("$CFG->dirroot/group/lib.php");
106 $params = self
::validate_parameters(self
::create_groups_parameters(), array('groups'=>$groups));
108 $transaction = $DB->start_delegated_transaction();
112 foreach ($params['groups'] as $group) {
113 $group = (object)$group;
115 if (trim($group->name
) == '') {
116 throw new invalid_parameter_exception('Invalid group name');
118 if ($DB->get_record('groups', array('courseid'=>$group->courseid
, 'name'=>$group->name
))) {
119 throw new invalid_parameter_exception('Group with the same name already exists in the course');
122 // now security checks
123 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
125 self
::validate_context($context);
126 } catch (Exception
$e) {
127 $exceptionparam = new stdClass();
128 $exceptionparam->message
= $e->getMessage();
129 $exceptionparam->courseid
= $group->courseid
;
130 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
132 require_capability('moodle/course:managegroups', $context);
135 $group->descriptionformat
= util
::validate_format($group->descriptionformat
);
137 // Validate visibility.
138 self
::validate_visibility($group->visibility
);
141 if (!empty($group->customfields
)) {
142 foreach ($group->customfields
as $field) {
143 $fieldname = self
::build_custom_field_name($field['shortname']);
144 $group->{$fieldname} = $field['value'];
148 // finally create the group
149 $group->id
= groups_create_group($group, false);
150 if (!isset($group->enrolmentkey
)) {
151 $group->enrolmentkey
= '';
153 if (!isset($group->idnumber
)) {
154 $group->idnumber
= '';
157 $groups[] = (array)$group;
160 $transaction->allow_commit();
166 * Returns description of method result value
168 * @return \core_external\external_description
171 public static function create_groups_returns() {
172 return new external_multiple_structure(
173 new external_single_structure(
175 'id' => new external_value(PARAM_INT
, 'group record id'),
176 'courseid' => new external_value(PARAM_INT
, 'id of course'),
177 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
178 'description' => new external_value(PARAM_RAW
, 'group description text'),
179 'descriptionformat' => new external_format_value('description'),
180 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase'),
181 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
182 'visibility' => new external_value(PARAM_INT
,
183 'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. '
184 . '3 = Membership is hidden.'),
185 'participation' => new external_value(PARAM_BOOL
, 'participation mode'),
186 'customfields' => self
::build_custom_fields_parameters_structure(),
188 ), 'List of group object. A group has an id, a courseid, a name, a description and an enrolment key.'
193 * Returns description of method parameters
195 * @return external_function_parameters
198 public static function get_groups_parameters() {
199 return new external_function_parameters(
201 'groupids' => new external_multiple_structure(new external_value(PARAM_INT
, 'Group ID')
202 ,'List of group id. A group id is an integer.'),
208 * Get groups definition specified by ids
210 * @param array $groupids arrays of group ids
211 * @return array of group objects (id, courseid, name, enrolmentkey)
214 public static function get_groups($groupids) {
215 $params = self
::validate_parameters(self
::get_groups_parameters(), array('groupids'=>$groupids));
218 $customfieldsdata = get_group_custom_fields_data($groupids);
219 foreach ($params['groupids'] as $groupid) {
221 $group = groups_get_group($groupid, 'id, courseid, name, idnumber, description, descriptionformat, enrolmentkey, '
222 . 'visibility, participation', MUST_EXIST
);
224 // now security checks
225 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
227 self
::validate_context($context);
228 } catch (Exception
$e) {
229 $exceptionparam = new stdClass();
230 $exceptionparam->message
= $e->getMessage();
231 $exceptionparam->courseid
= $group->courseid
;
232 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
234 require_capability('moodle/course:managegroups', $context);
236 $group->name
= \core_external\util
::format_string($group->name
, $context);
237 [$group->description
, $group->descriptionformat
] =
238 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
239 $context, 'group', 'description', $group->id
);
241 $group->customfields
= $customfieldsdata[$group->id
] ??
[];
242 $groups[] = (array)$group;
249 * Returns description of method result value
251 * @return \core_external\external_description
254 public static function get_groups_returns() {
255 return new external_multiple_structure(
256 new external_single_structure(
258 'id' => new external_value(PARAM_INT
, 'group record id'),
259 'courseid' => new external_value(PARAM_INT
, 'id of course'),
260 'name' => new external_value(PARAM_TEXT
, 'group name'),
261 'description' => new external_value(PARAM_RAW
, 'group description text'),
262 'descriptionformat' => new external_format_value('description'),
263 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase'),
264 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
265 'visibility' => new external_value(PARAM_INT
,
266 'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. '
267 . '3 = Membership is hidden.'),
268 'participation' => new external_value(PARAM_BOOL
, 'participation mode'),
269 'customfields' => self
::build_custom_fields_returns_structure(),
276 * Returns description of method parameters
278 * @return external_function_parameters
281 public static function get_course_groups_parameters() {
282 return new external_function_parameters(
284 'courseid' => new external_value(PARAM_INT
, 'id of course'),
290 * Get all groups in the specified course
292 * @param int $courseid id of course
293 * @return array of group objects (id, courseid, name, enrolmentkey)
296 public static function get_course_groups($courseid) {
297 $params = self
::validate_parameters(self
::get_course_groups_parameters(), array('courseid'=>$courseid));
299 // now security checks
300 $context = context_course
::instance($params['courseid'], IGNORE_MISSING
);
302 self
::validate_context($context);
303 } catch (Exception
$e) {
304 $exceptionparam = new stdClass();
305 $exceptionparam->message
= $e->getMessage();
306 $exceptionparam->courseid
= $params['courseid'];
307 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
309 require_capability('moodle/course:managegroups', $context);
311 $gs = groups_get_all_groups($params['courseid'], 0, 0,
312 'g.id, g.courseid, g.name, g.idnumber, g.description, g.descriptionformat, g.enrolmentkey, '
313 . 'g.visibility, g.participation');
316 foreach ($gs as $group) {
317 $group->name
= \core_external\util
::format_string($group->name
, $context);
318 [$group->description
, $group->descriptionformat
] =
319 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
320 $context, 'group', 'description', $group->id
);
321 $groups[] = (array)$group;
328 * Returns description of method result value
330 * @return \core_external\external_description
333 public static function get_course_groups_returns() {
334 return new external_multiple_structure(
335 new external_single_structure(
337 'id' => new external_value(PARAM_INT
, 'group record id'),
338 'courseid' => new external_value(PARAM_INT
, 'id of course'),
339 'name' => new external_value(PARAM_TEXT
, 'group name'),
340 'description' => new external_value(PARAM_RAW
, 'group description text'),
341 'descriptionformat' => new external_format_value('description'),
342 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase'),
343 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
344 'visibility' => new external_value(PARAM_INT
,
345 'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. '
346 . '3 = Membership is hidden.'),
347 'participation' => new external_value(PARAM_BOOL
, 'participation mode'),
354 * Returns description of method parameters
356 * @return external_function_parameters
359 public static function delete_groups_parameters() {
360 return new external_function_parameters(
362 'groupids' => new external_multiple_structure(new external_value(PARAM_INT
, 'Group ID')),
370 * @param array $groupids array of group ids
373 public static function delete_groups($groupids) {
375 require_once("$CFG->dirroot/group/lib.php");
377 $params = self
::validate_parameters(self
::delete_groups_parameters(), array('groupids'=>$groupids));
379 $transaction = $DB->start_delegated_transaction();
381 foreach ($params['groupids'] as $groupid) {
383 $groupid = validate_param($groupid, PARAM_INT
);
384 if (!$group = groups_get_group($groupid, '*', IGNORE_MISSING
)) {
385 // silently ignore attempts to delete nonexisting groups
389 // now security checks
390 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
392 self
::validate_context($context);
393 } catch (Exception
$e) {
394 $exceptionparam = new stdClass();
395 $exceptionparam->message
= $e->getMessage();
396 $exceptionparam->courseid
= $group->courseid
;
397 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
399 require_capability('moodle/course:managegroups', $context);
401 groups_delete_group($group);
404 $transaction->allow_commit();
408 * Returns description of method result value
413 public static function delete_groups_returns() {
419 * Returns description of method parameters
421 * @return external_function_parameters
424 public static function get_group_members_parameters() {
425 return new external_function_parameters(
427 'groupids' => new external_multiple_structure(new external_value(PARAM_INT
, 'Group ID')),
433 * Return all members for a group
435 * @param array $groupids array of group ids
436 * @return array with group id keys containing arrays of user ids
439 public static function get_group_members($groupids) {
442 $params = self
::validate_parameters(self
::get_group_members_parameters(), array('groupids'=>$groupids));
444 foreach ($params['groupids'] as $groupid) {
446 $group = groups_get_group($groupid, 'id, courseid, name, enrolmentkey', MUST_EXIST
);
447 // now security checks
448 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
450 self
::validate_context($context);
451 } catch (Exception
$e) {
452 $exceptionparam = new stdClass();
453 $exceptionparam->message
= $e->getMessage();
454 $exceptionparam->courseid
= $group->courseid
;
455 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
457 require_capability('moodle/course:managegroups', $context);
459 $groupmembers = groups_get_members($group->id
, 'u.id', 'lastname ASC, firstname ASC');
461 $members[] = array('groupid'=>$groupid, 'userids'=>array_keys($groupmembers));
468 * Returns description of method result value
470 * @return \core_external\external_description
473 public static function get_group_members_returns() {
474 return new external_multiple_structure(
475 new external_single_structure(
477 'groupid' => new external_value(PARAM_INT
, 'group record id'),
478 'userids' => new external_multiple_structure(new external_value(PARAM_INT
, 'user id')),
486 * Returns description of method parameters
488 * @return external_function_parameters
491 public static function add_group_members_parameters() {
492 return new external_function_parameters(
494 'members'=> new external_multiple_structure(
495 new external_single_structure(
497 'groupid' => new external_value(PARAM_INT
, 'group record id'),
498 'userid' => new external_value(PARAM_INT
, 'user id'),
509 * @param array $members of arrays with keys userid, groupid
512 public static function add_group_members($members) {
514 require_once("$CFG->dirroot/group/lib.php");
516 $params = self
::validate_parameters(self
::add_group_members_parameters(), array('members'=>$members));
518 $transaction = $DB->start_delegated_transaction();
519 foreach ($params['members'] as $member) {
521 $groupid = $member['groupid'];
522 $userid = $member['userid'];
524 $group = groups_get_group($groupid, '*', MUST_EXIST
);
525 $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0, 'mnethostid'=>$CFG->mnet_localhost_id
), '*', MUST_EXIST
);
527 // now security checks
528 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
530 self
::validate_context($context);
531 } catch (Exception
$e) {
532 $exceptionparam = new stdClass();
533 $exceptionparam->message
= $e->getMessage();
534 $exceptionparam->courseid
= $group->courseid
;
535 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
537 require_capability('moodle/course:managegroups', $context);
539 // now make sure user is enrolled in course - this is mandatory requirement,
540 // unfortunately this is slow
541 if (!is_enrolled($context, $userid)) {
542 throw new invalid_parameter_exception('Only enrolled users may be members of groups');
545 groups_add_member($group, $user);
548 $transaction->allow_commit();
552 * Returns description of method result value
557 public static function add_group_members_returns() {
563 * Returns description of method parameters
565 * @return external_function_parameters
568 public static function delete_group_members_parameters() {
569 return new external_function_parameters(
571 'members'=> new external_multiple_structure(
572 new external_single_structure(
574 'groupid' => new external_value(PARAM_INT
, 'group record id'),
575 'userid' => new external_value(PARAM_INT
, 'user id'),
584 * Delete group members
586 * @param array $members of arrays with keys userid, groupid
589 public static function delete_group_members($members) {
591 require_once("$CFG->dirroot/group/lib.php");
593 $params = self
::validate_parameters(self
::delete_group_members_parameters(), array('members'=>$members));
595 $transaction = $DB->start_delegated_transaction();
597 foreach ($params['members'] as $member) {
599 $groupid = $member['groupid'];
600 $userid = $member['userid'];
602 $group = groups_get_group($groupid, '*', MUST_EXIST
);
603 $user = $DB->get_record('user', array('id'=>$userid, 'deleted'=>0, 'mnethostid'=>$CFG->mnet_localhost_id
), '*', MUST_EXIST
);
605 // now security checks
606 $context = context_course
::instance($group->courseid
, IGNORE_MISSING
);
608 self
::validate_context($context);
609 } catch (Exception
$e) {
610 $exceptionparam = new stdClass();
611 $exceptionparam->message
= $e->getMessage();
612 $exceptionparam->courseid
= $group->courseid
;
613 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
615 require_capability('moodle/course:managegroups', $context);
617 if (!groups_remove_member_allowed($group, $user)) {
618 $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context));
619 throw new moodle_exception('errorremovenotpermitted', 'group', '', $fullname);
621 groups_remove_member($group, $user);
624 $transaction->allow_commit();
628 * Returns description of method result value
633 public static function delete_group_members_returns() {
638 * Returns description of method parameters
640 * @return external_function_parameters
643 public static function create_groupings_parameters() {
644 return new external_function_parameters(
646 'groupings' => new external_multiple_structure(
647 new external_single_structure(
649 'courseid' => new external_value(PARAM_INT
, 'id of course'),
650 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
651 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
652 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT
),
653 'idnumber' => new external_value(PARAM_RAW
, 'id number', VALUE_OPTIONAL
),
654 'customfields' => self
::build_custom_fields_parameters_structure(),
656 ), 'List of grouping object. A grouping has a courseid, a name and a description.'
665 * @param array $groupings array of grouping description arrays (with keys groupname and courseid)
666 * @return array of newly created groupings
669 public static function create_groupings($groupings) {
671 require_once("$CFG->dirroot/group/lib.php");
673 $params = self
::validate_parameters(self
::create_groupings_parameters(), array('groupings'=>$groupings));
675 $transaction = $DB->start_delegated_transaction();
677 $groupings = array();
679 foreach ($params['groupings'] as $grouping) {
680 $grouping = (object)$grouping;
682 if (trim($grouping->name
) == '') {
683 throw new invalid_parameter_exception('Invalid grouping name');
685 if ($DB->count_records('groupings', array('courseid'=>$grouping->courseid
, 'name'=>$grouping->name
))) {
686 throw new invalid_parameter_exception('Grouping with the same name already exists in the course');
689 // Now security checks .
690 $context = context_course
::instance($grouping->courseid
);
692 self
::validate_context($context);
693 } catch (Exception
$e) {
694 $exceptionparam = new stdClass();
695 $exceptionparam->message
= $e->getMessage();
696 $exceptionparam->courseid
= $grouping->courseid
;
697 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
699 require_capability('moodle/course:managegroups', $context);
701 $grouping->descriptionformat
= util
::validate_format($grouping->descriptionformat
);
704 if (!empty($grouping->customfields
)) {
705 foreach ($grouping->customfields
as $field) {
706 $fieldname = self
::build_custom_field_name($field['shortname']);
707 $grouping->{$fieldname} = $field['value'];
711 // Finally create the grouping.
712 $grouping->id
= groups_create_grouping($grouping);
713 $groupings[] = (array)$grouping;
716 $transaction->allow_commit();
722 * Returns description of method result value
724 * @return \core_external\external_description
727 public static function create_groupings_returns() {
728 return new external_multiple_structure(
729 new external_single_structure(
731 'id' => new external_value(PARAM_INT
, 'grouping record id'),
732 'courseid' => new external_value(PARAM_INT
, 'id of course'),
733 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
734 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
735 'descriptionformat' => new external_format_value('description'),
736 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
737 'customfields' => self
::build_custom_fields_parameters_structure(),
739 ), 'List of grouping object. A grouping has an id, a courseid, a name and a description.'
744 * Returns description of method parameters
746 * @return external_function_parameters
749 public static function update_groupings_parameters() {
750 return new external_function_parameters(
752 'groupings' => new external_multiple_structure(
753 new external_single_structure(
755 'id' => new external_value(PARAM_INT
, 'id of grouping'),
756 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
757 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
758 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT
),
759 'idnumber' => new external_value(PARAM_RAW
, 'id number', VALUE_OPTIONAL
),
760 'customfields' => self
::build_custom_fields_parameters_structure(),
762 ), 'List of grouping object. A grouping has a courseid, a name and a description.'
771 * @param array $groupings array of grouping description arrays (with keys groupname and courseid)
772 * @return array of newly updated groupings
775 public static function update_groupings($groupings) {
777 require_once("$CFG->dirroot/group/lib.php");
779 $params = self
::validate_parameters(self
::update_groupings_parameters(), array('groupings'=>$groupings));
781 $transaction = $DB->start_delegated_transaction();
783 foreach ($params['groupings'] as $grouping) {
784 $grouping = (object)$grouping;
786 if (trim($grouping->name
) == '') {
787 throw new invalid_parameter_exception('Invalid grouping name');
790 if (! $currentgrouping = $DB->get_record('groupings', array('id'=>$grouping->id
))) {
791 throw new invalid_parameter_exception("Grouping $grouping->id does not exist in the course");
794 // Check if the new modified grouping name already exists in the course.
795 if ($grouping->name
!= $currentgrouping->name
and
796 $DB->count_records('groupings', array('courseid'=>$currentgrouping->courseid
, 'name'=>$grouping->name
))) {
797 throw new invalid_parameter_exception('A different grouping with the same name already exists in the course');
800 $grouping->courseid
= $currentgrouping->courseid
;
802 // Now security checks.
803 $context = context_course
::instance($grouping->courseid
);
805 self
::validate_context($context);
806 } catch (Exception
$e) {
807 $exceptionparam = new stdClass();
808 $exceptionparam->message
= $e->getMessage();
809 $exceptionparam->courseid
= $grouping->courseid
;
810 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
812 require_capability('moodle/course:managegroups', $context);
814 // We must force allways FORMAT_HTML.
815 $grouping->descriptionformat
= util
::validate_format($grouping->descriptionformat
);
818 if (!empty($grouping->customfields
)) {
819 foreach ($grouping->customfields
as $field) {
820 $fieldname = self
::build_custom_field_name($field['shortname']);
821 $grouping->{$fieldname} = $field['value'];
825 // Finally update the grouping.
826 groups_update_grouping($grouping);
829 $transaction->allow_commit();
835 * Returns description of method result value
837 * @return \core_external\external_description
840 public static function update_groupings_returns() {
845 * Returns description of method parameters
847 * @return external_function_parameters
850 public static function get_groupings_parameters() {
851 return new external_function_parameters(
853 'groupingids' => new external_multiple_structure(new external_value(PARAM_INT
, 'grouping ID')
854 , 'List of grouping id. A grouping id is an integer.'),
855 'returngroups' => new external_value(PARAM_BOOL
, 'return associated groups', VALUE_DEFAULT
, 0)
861 * Get groupings definition specified by ids
863 * @param array $groupingids arrays of grouping ids
864 * @param boolean $returngroups return the associated groups if true. The default is false.
865 * @return array of grouping objects (id, courseid, name)
868 public static function get_groupings($groupingids, $returngroups = false) {
870 require_once("$CFG->dirroot/group/lib.php");
871 require_once("$CFG->libdir/filelib.php");
873 $params = self
::validate_parameters(self
::get_groupings_parameters(),
874 array('groupingids' => $groupingids,
875 'returngroups' => $returngroups));
877 $groupings = array();
878 $groupingcustomfieldsdata = get_grouping_custom_fields_data($groupingids);
879 foreach ($params['groupingids'] as $groupingid) {
881 $grouping = groups_get_grouping($groupingid, '*', MUST_EXIST
);
883 // Now security checks.
884 $context = context_course
::instance($grouping->courseid
);
886 self
::validate_context($context);
887 } catch (Exception
$e) {
888 $exceptionparam = new stdClass();
889 $exceptionparam->message
= $e->getMessage();
890 $exceptionparam->courseid
= $grouping->courseid
;
891 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
893 require_capability('moodle/course:managegroups', $context);
895 list($grouping->description
, $grouping->descriptionformat
) =
896 \core_external\util
::format_text($grouping->description
, $grouping->descriptionformat
,
897 $context, 'grouping', 'description', $grouping->id
);
899 $grouping->customfields
= $groupingcustomfieldsdata[$grouping->id
] ??
[];
900 $groupingarray = (array)$grouping;
902 if ($params['returngroups']) {
903 $grouprecords = $DB->get_records_sql("SELECT * FROM {groups} g INNER JOIN {groupings_groups} gg ".
904 "ON g.id = gg.groupid WHERE gg.groupingid = ? ".
905 "ORDER BY groupid", array($groupingid));
909 foreach ($grouprecords as $grouprecord) {
910 list($grouprecord->description
, $grouprecord->descriptionformat
) =
911 \core_external\util
::format_text($grouprecord->description
, $grouprecord->descriptionformat
,
912 $context, 'group', 'description', $grouprecord->groupid
);
913 $groups[] = array('id' => $grouprecord->groupid
,
914 'name' => $grouprecord->name
,
915 'idnumber' => $grouprecord->idnumber
,
916 'description' => $grouprecord->description
,
917 'descriptionformat' => $grouprecord->descriptionformat
,
918 'enrolmentkey' => $grouprecord->enrolmentkey
,
919 'courseid' => $grouprecord->courseid
921 $groupids[] = $grouprecord->groupid
;
923 $groupcustomfieldsdata = get_group_custom_fields_data($groupids);
924 foreach ($groups as $i => $group) {
925 $groups[$i]['customfields'] = $groupcustomfieldsdata[$group['id']] ??
[];
927 $groupingarray['groups'] = $groups;
930 $groupings[] = $groupingarray;
937 * Returns description of method result value
939 * @return \core_external\external_description
942 public static function get_groupings_returns() {
943 return new external_multiple_structure(
944 new external_single_structure(
946 'id' => new external_value(PARAM_INT
, 'grouping record id'),
947 'courseid' => new external_value(PARAM_INT
, 'id of course'),
948 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
949 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
950 'descriptionformat' => new external_format_value('description'),
951 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
952 'customfields' => self
::build_custom_fields_returns_structure(),
953 'groups' => new external_multiple_structure(
954 new external_single_structure(
956 'id' => new external_value(PARAM_INT
, 'group record id'),
957 'courseid' => new external_value(PARAM_INT
, 'id of course'),
958 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
959 'description' => new external_value(PARAM_RAW
, 'group description text'),
960 'descriptionformat' => new external_format_value('description'),
961 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase'),
962 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
963 'customfields' => self
::build_custom_fields_returns_structure(),
966 'optional groups', VALUE_OPTIONAL
)
973 * Returns description of method parameters
975 * @return external_function_parameters
978 public static function get_course_groupings_parameters() {
979 return new external_function_parameters(
981 'courseid' => new external_value(PARAM_INT
, 'id of course'),
987 * Get all groupings in the specified course
989 * @param int $courseid id of course
990 * @return array of grouping objects (id, courseid, name, enrolmentkey)
993 public static function get_course_groupings($courseid) {
995 require_once("$CFG->dirroot/group/lib.php");
996 require_once("$CFG->libdir/filelib.php");
998 $params = self
::validate_parameters(self
::get_course_groupings_parameters(), array('courseid'=>$courseid));
1000 // Now security checks.
1001 $context = context_course
::instance($params['courseid']);
1004 self
::validate_context($context);
1005 } catch (Exception
$e) {
1006 $exceptionparam = new stdClass();
1007 $exceptionparam->message
= $e->getMessage();
1008 $exceptionparam->courseid
= $params['courseid'];
1009 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
1011 require_capability('moodle/course:managegroups', $context);
1013 $gs = groups_get_all_groupings($params['courseid']);
1015 $groupings = array();
1016 foreach ($gs as $grouping) {
1017 list($grouping->description
, $grouping->descriptionformat
) =
1018 \core_external\util
::format_text($grouping->description
, $grouping->descriptionformat
,
1019 $context, 'grouping', 'description', $grouping->id
);
1020 $groupings[] = (array)$grouping;
1027 * Returns description of method result value
1029 * @return \core_external\external_description
1032 public static function get_course_groupings_returns() {
1033 return new external_multiple_structure(
1034 new external_single_structure(
1036 'id' => new external_value(PARAM_INT
, 'grouping record id'),
1037 'courseid' => new external_value(PARAM_INT
, 'id of course'),
1038 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
1039 'description' => new external_value(PARAM_RAW
, 'grouping description text'),
1040 'descriptionformat' => new external_format_value('description'),
1041 'idnumber' => new external_value(PARAM_RAW
, 'id number')
1048 * Returns description of method parameters
1050 * @return external_function_parameters
1053 public static function delete_groupings_parameters() {
1054 return new external_function_parameters(
1056 'groupingids' => new external_multiple_structure(new external_value(PARAM_INT
, 'grouping ID')),
1064 * @param array $groupingids array of grouping ids
1068 public static function delete_groupings($groupingids) {
1070 require_once("$CFG->dirroot/group/lib.php");
1072 $params = self
::validate_parameters(self
::delete_groupings_parameters(), array('groupingids'=>$groupingids));
1074 $transaction = $DB->start_delegated_transaction();
1076 foreach ($params['groupingids'] as $groupingid) {
1078 if (!$grouping = groups_get_grouping($groupingid)) {
1079 // Silently ignore attempts to delete nonexisting groupings.
1083 // Now security checks.
1084 $context = context_course
::instance($grouping->courseid
);
1086 self
::validate_context($context);
1087 } catch (Exception
$e) {
1088 $exceptionparam = new stdClass();
1089 $exceptionparam->message
= $e->getMessage();
1090 $exceptionparam->courseid
= $grouping->courseid
;
1091 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
1093 require_capability('moodle/course:managegroups', $context);
1095 groups_delete_grouping($grouping);
1098 $transaction->allow_commit();
1102 * Returns description of method result value
1104 * @return \core_external\external_description
1107 public static function delete_groupings_returns() {
1112 * Returns description of method parameters
1114 * @return external_function_parameters
1117 public static function assign_grouping_parameters() {
1118 return new external_function_parameters(
1120 'assignments'=> new external_multiple_structure(
1121 new external_single_structure(
1123 'groupingid' => new external_value(PARAM_INT
, 'grouping record id'),
1124 'groupid' => new external_value(PARAM_INT
, 'group record id'),
1133 * Assign a group to a grouping
1135 * @param array $assignments of arrays with keys groupid, groupingid
1139 public static function assign_grouping($assignments) {
1141 require_once("$CFG->dirroot/group/lib.php");
1143 $params = self
::validate_parameters(self
::assign_grouping_parameters(), array('assignments'=>$assignments));
1145 $transaction = $DB->start_delegated_transaction();
1146 foreach ($params['assignments'] as $assignment) {
1148 $groupingid = $assignment['groupingid'];
1149 $groupid = $assignment['groupid'];
1151 $grouping = groups_get_grouping($groupingid, 'id, courseid', MUST_EXIST
);
1152 $group = groups_get_group($groupid, 'id, courseid', MUST_EXIST
);
1154 if ($DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) {
1155 // Continue silently if the group is yet assigned to the grouping.
1159 // Now security checks.
1160 $context = context_course
::instance($grouping->courseid
);
1162 self
::validate_context($context);
1163 } catch (Exception
$e) {
1164 $exceptionparam = new stdClass();
1165 $exceptionparam->message
= $e->getMessage();
1166 $exceptionparam->courseid
= $group->courseid
;
1167 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
1169 require_capability('moodle/course:managegroups', $context);
1171 groups_assign_grouping($groupingid, $groupid);
1174 $transaction->allow_commit();
1178 * Returns description of method result value
1183 public static function assign_grouping_returns() {
1188 * Returns description of method parameters
1190 * @return external_function_parameters
1193 public static function unassign_grouping_parameters() {
1194 return new external_function_parameters(
1196 'unassignments'=> new external_multiple_structure(
1197 new external_single_structure(
1199 'groupingid' => new external_value(PARAM_INT
, 'grouping record id'),
1200 'groupid' => new external_value(PARAM_INT
, 'group record id'),
1209 * Unassign a group from a grouping
1211 * @param array $unassignments of arrays with keys groupid, groupingid
1215 public static function unassign_grouping($unassignments) {
1217 require_once("$CFG->dirroot/group/lib.php");
1219 $params = self
::validate_parameters(self
::unassign_grouping_parameters(), array('unassignments'=>$unassignments));
1221 $transaction = $DB->start_delegated_transaction();
1222 foreach ($params['unassignments'] as $unassignment) {
1224 $groupingid = $unassignment['groupingid'];
1225 $groupid = $unassignment['groupid'];
1227 $grouping = groups_get_grouping($groupingid, 'id, courseid', MUST_EXIST
);
1228 $group = groups_get_group($groupid, 'id, courseid', MUST_EXIST
);
1230 if (!$DB->record_exists('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid))) {
1231 // Continue silently if the group is not assigned to the grouping.
1235 // Now security checks.
1236 $context = context_course
::instance($grouping->courseid
);
1238 self
::validate_context($context);
1239 } catch (Exception
$e) {
1240 $exceptionparam = new stdClass();
1241 $exceptionparam->message
= $e->getMessage();
1242 $exceptionparam->courseid
= $group->courseid
;
1243 throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
1245 require_capability('moodle/course:managegroups', $context);
1247 groups_unassign_grouping($groupingid, $groupid);
1250 $transaction->allow_commit();
1254 * Returns description of method result value
1259 public static function unassign_grouping_returns() {
1264 * Returns description of method parameters
1266 * @return external_function_parameters
1269 public static function get_course_user_groups_parameters() {
1270 return new external_function_parameters(
1272 'courseid' => new external_value(PARAM_INT
,
1273 'Id of course (empty or 0 for all the courses where the user is enrolled).', VALUE_DEFAULT
, 0),
1274 'userid' => new external_value(PARAM_INT
, 'Id of user (empty or 0 for current user).', VALUE_DEFAULT
, 0),
1275 'groupingid' => new external_value(PARAM_INT
, 'returns only groups in the specified grouping', VALUE_DEFAULT
, 0)
1281 * Get all groups in the specified course for the specified user.
1283 * @throws moodle_exception
1284 * @param int $courseid id of course.
1285 * @param int $userid id of user.
1286 * @param int $groupingid optional returns only groups in the specified grouping.
1287 * @return array of group objects (id, name, description, format) and possible warnings.
1290 public static function get_course_user_groups($courseid = 0, $userid = 0, $groupingid = 0) {
1293 // Warnings array, it can be empty at the end but is mandatory.
1294 $warnings = array();
1297 'courseid' => $courseid,
1298 'userid' => $userid,
1299 'groupingid' => $groupingid
1301 $params = self
::validate_parameters(self
::get_course_user_groups_parameters(), $params);
1303 $courseid = $params['courseid'];
1304 $userid = $params['userid'];
1305 $groupingid = $params['groupingid'];
1308 if (empty($userid)) {
1309 $userid = $USER->id
;
1311 $user = core_user
::get_user($userid, '*', MUST_EXIST
);
1312 core_user
::require_active_user($user);
1316 if (empty($courseid)) {
1317 $courses = enrol_get_users_courses($userid, true);
1318 $checkenrolments = false; // No need to check enrolments here since they are my courses.
1320 $courses = array($courseid => get_course($courseid));
1321 $checkenrolments = true;
1325 list($courses, $warnings) = util
::validate_courses(array_keys($courses), $courses, true);
1327 $usergroups = array();
1328 foreach ($courses as $course) {
1329 // Check if we have permissions for retrieve the information.
1330 if ($userid != $USER->id
&& !has_capability('moodle/course:managegroups', $course->context
)) {
1331 $warnings[] = array(
1333 'itemid' => $course->id
,
1334 'warningcode' => 'cannotmanagegroups',
1335 'message' => "User $USER->id cannot manage groups in course $course->id",
1340 // Check if the user being check is enrolled in the given course.
1341 if ($checkenrolments && !is_enrolled($course->context
, $userid)) {
1342 // We return a warning because the function does not fail for not enrolled users.
1343 $warnings[] = array(
1345 'itemid' => $course->id
,
1346 'warningcode' => 'notenrolled',
1347 'message' => "User $userid is not enrolled in course $course->id",
1351 $groups = groups_get_all_groups($course->id
, $userid, $groupingid,
1352 'g.id, g.name, g.description, g.descriptionformat, g.idnumber');
1354 foreach ($groups as $group) {
1355 $group->name
= \core_external\util
::format_string($group->name
, $course->context
);
1356 [$group->description
, $group->descriptionformat
] =
1357 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
1358 $course->context
, 'group', 'description', $group->id
);
1359 $group->courseid
= $course->id
;
1360 $usergroups[] = $group;
1365 'groups' => $usergroups,
1366 'warnings' => $warnings
1372 * Returns description of method result value.
1374 * @return \core_external\external_description A single structure containing groups and possible warnings.
1377 public static function get_course_user_groups_returns() {
1378 return new external_single_structure(
1380 'groups' => new external_multiple_structure(self
::group_description()),
1381 'warnings' => new external_warnings(),
1387 * Create group return value description.
1389 * @return external_single_structure The group description
1391 public static function group_description() {
1392 return new external_single_structure(
1394 'id' => new external_value(PARAM_INT
, 'group record id'),
1395 'name' => new external_value(PARAM_TEXT
, 'group name'),
1396 'description' => new external_value(PARAM_RAW
, 'group description text'),
1397 'descriptionformat' => new external_format_value('description'),
1398 'idnumber' => new external_value(PARAM_RAW
, 'id number'),
1399 'courseid' => new external_value(PARAM_INT
, 'course id', VALUE_OPTIONAL
),
1405 * Returns description of method parameters
1407 * @return external_function_parameters
1410 public static function get_activity_allowed_groups_parameters() {
1411 return new external_function_parameters(
1413 'cmid' => new external_value(PARAM_INT
, 'course module id'),
1414 'userid' => new external_value(PARAM_INT
, 'id of user, empty for current user', VALUE_DEFAULT
, 0)
1420 * Gets a list of groups that the user is allowed to access within the specified activity.
1422 * @throws moodle_exception
1423 * @param int $cmid course module id
1424 * @param int $userid id of user.
1425 * @return array of group objects (id, name, description, format) and possible warnings.
1428 public static function get_activity_allowed_groups($cmid, $userid = 0) {
1431 // Warnings array, it can be empty at the end but is mandatory.
1432 $warnings = array();
1438 $params = self
::validate_parameters(self
::get_activity_allowed_groups_parameters(), $params);
1439 $cmid = $params['cmid'];
1440 $userid = $params['userid'];
1442 $cm = get_coursemodule_from_id(null, $cmid, 0, false, MUST_EXIST
);
1445 $context = context_module
::instance($cm->id
);
1446 $coursecontext = context_course
::instance($cm->course
);
1447 self
::validate_context($context);
1449 if (empty($userid)) {
1450 $userid = $USER->id
;
1453 $user = core_user
::get_user($userid, '*', MUST_EXIST
);
1454 core_user
::require_active_user($user);
1456 // Check if we have permissions for retrieve the information.
1457 if ($user->id
!= $USER->id
) {
1458 if (!has_capability('moodle/course:managegroups', $context)) {
1459 throw new moodle_exception('accessdenied', 'admin');
1462 // Validate if the user is enrolled in the course.
1463 $course = get_course($cm->course
);
1464 if (!can_access_course($course, $user, '', true)) {
1465 // We return a warning because the function does not fail for not enrolled users.
1467 $warning['item'] = 'course';
1468 $warning['itemid'] = $cm->course
;
1469 $warning['warningcode'] = '1';
1470 $warning['message'] = "User $user->id cannot access course $cm->course";
1471 $warnings[] = $warning;
1475 $usergroups = array();
1476 if (empty($warnings)) {
1477 $groups = groups_get_activity_allowed_groups($cm, $user->id
);
1479 foreach ($groups as $group) {
1480 $group->name
= \core_external\util
::format_string($group->name
, $coursecontext);
1481 [$group->description
, $group->descriptionformat
] =
1482 \core_external\util
::format_text($group->description
, $group->descriptionformat
,
1483 $coursecontext, 'group', 'description', $group->id
);
1484 $group->courseid
= $cm->course
;
1485 $usergroups[] = $group;
1490 'groups' => $usergroups,
1491 'canaccessallgroups' => has_capability('moodle/site:accessallgroups', $context, $user),
1492 'warnings' => $warnings
1498 * Returns description of method result value.
1500 * @return \core_external\external_description A single structure containing groups and possible warnings.
1503 public static function get_activity_allowed_groups_returns() {
1504 return new external_single_structure(
1506 'groups' => new external_multiple_structure(self
::group_description()),
1507 'canaccessallgroups' => new external_value(PARAM_BOOL
,
1508 'Whether the user will be able to access all the activity groups.', VALUE_OPTIONAL
),
1509 'warnings' => new external_warnings(),
1515 * Returns description of method parameters
1517 * @return external_function_parameters
1520 public static function get_activity_groupmode_parameters() {
1521 return new external_function_parameters(
1523 'cmid' => new external_value(PARAM_INT
, 'course module id')
1529 * Returns effective groupmode used in a given activity.
1531 * @throws moodle_exception
1532 * @param int $cmid course module id.
1533 * @return array containing the group mode and possible warnings.
1535 * @throws moodle_exception
1537 public static function get_activity_groupmode($cmid) {
1540 // Warnings array, it can be empty at the end but is mandatory.
1541 $warnings = array();
1546 $params = self
::validate_parameters(self
::get_activity_groupmode_parameters(), $params);
1547 $cmid = $params['cmid'];
1549 $cm = get_coursemodule_from_id(null, $cmid, 0, false, MUST_EXIST
);
1552 $context = context_module
::instance($cm->id
);
1553 self
::validate_context($context);
1555 $groupmode = groups_get_activity_groupmode($cm);
1558 'groupmode' => $groupmode,
1559 'warnings' => $warnings
1565 * Returns description of method result value.
1567 * @return \core_external\external_description
1570 public static function get_activity_groupmode_returns() {
1571 return new external_single_structure(
1573 'groupmode' => new external_value(PARAM_INT
, 'group mode:
1574 0 for no groups, 1 for separate groups, 2 for visible groups'),
1575 'warnings' => new external_warnings(),
1581 * Returns description of method parameters
1583 * @return external_function_parameters
1586 public static function update_groups_parameters() {
1587 return new external_function_parameters(
1589 'groups' => new external_multiple_structure(
1590 new external_single_structure(
1592 'id' => new external_value(PARAM_INT
, 'ID of the group'),
1593 'name' => new external_value(PARAM_TEXT
, 'multilang compatible name, course unique'),
1594 'description' => new external_value(PARAM_RAW
, 'group description text', VALUE_OPTIONAL
),
1595 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT
),
1596 'enrolmentkey' => new external_value(PARAM_RAW
, 'group enrol secret phrase', VALUE_OPTIONAL
),
1597 'idnumber' => new external_value(PARAM_RAW
, 'id number', VALUE_OPTIONAL
),
1598 'visibility' => new external_value(PARAM_TEXT
,
1599 'group visibility mode. 0 = Visible to all. 1 = Visible to members. '
1600 . '2 = See own membership. 3 = Membership is hidden.', VALUE_OPTIONAL
),
1601 'participation' => new external_value(PARAM_BOOL
,
1602 'activity participation enabled? Only for "all" and "members" visibility', VALUE_OPTIONAL
),
1603 'customfields' => self
::build_custom_fields_parameters_structure(),
1605 ), 'List of group objects. A group is found by the id, then all other details provided will be updated.'
1614 * @param array $groups
1618 public static function update_groups($groups) {
1620 require_once("$CFG->dirroot/group/lib.php");
1622 $params = self
::validate_parameters(self
::update_groups_parameters(), array('groups' => $groups));
1624 $transaction = $DB->start_delegated_transaction();
1626 foreach ($params['groups'] as $group) {
1627 $group = (object) $group;
1629 if (trim($group->name
) == '') {
1630 throw new invalid_parameter_exception('Invalid group name');
1633 if (!$currentgroup = $DB->get_record('groups', array('id' => $group->id
))) {
1634 throw new invalid_parameter_exception("Group $group->id does not exist");
1637 // Check if the modified group name already exists in the course.
1638 if ($group->name
!= $currentgroup->name
and
1639 $DB->get_record('groups', array('courseid' => $currentgroup->courseid
, 'name' => $group->name
))) {
1640 throw new invalid_parameter_exception('A different group with the same name already exists in the course');
1643 if (isset($group->visibility
) ||
isset($group->participation
)) {
1644 $hasmembers = $DB->record_exists('groups_members', ['groupid' => $group->id
]);
1645 if (isset($group->visibility
)) {
1646 // Validate visibility.
1647 self
::validate_visibility($group->visibility
);
1648 if ($hasmembers && $group->visibility
!= $currentgroup->visibility
) {
1649 throw new invalid_parameter_exception(
1650 'The visibility of this group cannot be changed as it currently has members.');
1653 $group->visibility
= $currentgroup->visibility
;
1655 if (isset($group->participation
) && $hasmembers && $group->participation
!= $currentgroup->participation
) {
1656 throw new invalid_parameter_exception(
1657 'The participation mode of this group cannot be changed as it currently has members.');
1661 $group->courseid
= $currentgroup->courseid
;
1663 // Now security checks.
1664 $context = context_course
::instance($group->courseid
);
1666 self
::validate_context($context);
1667 } catch (Exception
$e) {
1668 $exceptionparam = new stdClass();
1669 $exceptionparam->message
= $e->getMessage();
1670 $exceptionparam->courseid
= $group->courseid
;
1671 throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
1673 require_capability('moodle/course:managegroups', $context);
1675 if (!empty($group->description
)) {
1676 $group->descriptionformat
= util
::validate_format($group->descriptionformat
);
1680 if (!empty($group->customfields
)) {
1681 foreach ($group->customfields
as $field) {
1682 $fieldname = self
::build_custom_field_name($field['shortname']);
1683 $group->{$fieldname} = $field['value'];
1687 groups_update_group($group);
1690 $transaction->allow_commit();
1696 * Returns description of method result value
1701 public static function update_groups_returns() {
1706 * Builds a structure for custom fields parameters.
1708 * @return \core_external\external_multiple_structure
1710 protected static function build_custom_fields_parameters_structure(): external_multiple_structure
{
1711 return new external_multiple_structure(
1712 new external_single_structure([
1713 'shortname' => new external_value(PARAM_ALPHANUMEXT
, 'The shortname of the custom field'),
1714 'value' => new external_value(PARAM_RAW
, 'The value of the custom field'),
1715 ]), 'Custom fields', VALUE_OPTIONAL
1720 * Builds a structure for custom fields returns.
1722 * @return \core_external\external_multiple_structure
1724 protected static function build_custom_fields_returns_structure(): external_multiple_structure
{
1725 return new external_multiple_structure(
1726 new external_single_structure([
1727 'name' => new external_value(PARAM_RAW
, 'The name of the custom field'),
1728 'shortname' => new external_value(PARAM_RAW
,
1729 'The shortname of the custom field - to be able to build the field class in the code'),
1730 'type' => new external_value(PARAM_ALPHANUMEXT
,
1731 'The type of the custom field - text field, checkbox...'),
1732 'valueraw' => new external_value(PARAM_RAW
, 'The raw value of the custom field'),
1733 'value' => new external_value(PARAM_RAW
, 'The value of the custom field'),
1734 ]), 'Custom fields', VALUE_OPTIONAL
1739 * Builds a suitable name of a custom field for a custom field handler based on provided shortname.
1741 * @param string $shortname shortname to use.
1744 protected static function build_custom_field_name(string $shortname): string {
1745 return 'customfield_' . $shortname;