Merge branch 'MDL-38424_m23' of git://github.com/kordan/moodle into MOODLE_23_STABLE
[moodle.git] / course / externallib.php
blob88c0693048e9e355d4a07620279192034c0db48f
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/>.
18 /**
19 * External course API
21 * @package core_course
22 * @category external
23 * @copyright 2009 Petr Skodak
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 defined('MOODLE_INTERNAL') || die;
29 require_once("$CFG->libdir/externallib.php");
31 /**
32 * Course external functions
34 * @package core_course
35 * @category external
36 * @copyright 2011 Jerome Mouneyrac
37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38 * @since Moodle 2.2
40 class core_course_external extends external_api {
42 /**
43 * Returns description of method parameters
45 * @return external_function_parameters
46 * @since Moodle 2.2
48 public static function get_course_contents_parameters() {
49 return new external_function_parameters(
50 array('courseid' => new external_value(PARAM_INT, 'course id'),
51 'options' => new external_multiple_structure (
52 new external_single_structure(
53 array('name' => new external_value(PARAM_ALPHANUM, 'option name'),
54 'value' => new external_value(PARAM_RAW, 'the value of the option, this param is personaly validated in the external function.')
56 ), 'Options, not used yet, might be used in later version', VALUE_DEFAULT, array())
61 /**
62 * Get course contents
64 * @param int $courseid course id
65 * @param array $options These options are not used yet, might be used in later version
66 * @return array
67 * @since Moodle 2.2
69 public static function get_course_contents($courseid, $options = array()) {
70 global $CFG, $DB;
71 require_once($CFG->dirroot . "/course/lib.php");
73 //validate parameter
74 $params = self::validate_parameters(self::get_course_contents_parameters(),
75 array('courseid' => $courseid, 'options' => $options));
77 //retrieve the course
78 $course = $DB->get_record('course', array('id' => $params['courseid']), '*', MUST_EXIST);
80 //check course format exist
81 if (!file_exists($CFG->dirroot . '/course/format/' . $course->format . '/lib.php')) {
82 throw new moodle_exception('cannotgetcoursecontents', 'webservice', '', null, get_string('courseformatnotfound', 'error', '', $course->format));
83 } else {
84 require_once($CFG->dirroot . '/course/format/' . $course->format . '/lib.php');
87 // now security checks
88 $context = get_context_instance(CONTEXT_COURSE, $course->id);
89 try {
90 self::validate_context($context);
91 } catch (Exception $e) {
92 $exceptionparam = new stdClass();
93 $exceptionparam->message = $e->getMessage();
94 $exceptionparam->courseid = $course->id;
95 throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
98 $canupdatecourse = has_capability('moodle/course:update', $context);
100 //create return value
101 $coursecontents = array();
103 if ($canupdatecourse or $course->visible
104 or has_capability('moodle/course:viewhiddencourses', $context)) {
106 //retrieve sections
107 $modinfo = get_fast_modinfo($course);
108 $sections = get_all_sections($course->id);
110 //for each sections (first displayed to last displayed)
111 foreach ($sections as $key => $section) {
113 $showsection = (has_capability('moodle/course:viewhiddensections', $context) or $section->visible or !$course->hiddensections);
114 if (!$showsection) {
115 continue;
118 // reset $sectioncontents
119 $sectionvalues = array();
120 $sectionvalues['id'] = $section->id;
121 $sectionvalues['name'] = get_section_name($course, $section);
122 $sectionvalues['visible'] = $section->visible;
123 list($sectionvalues['summary'], $sectionvalues['summaryformat']) =
124 external_format_text($section->summary, $section->summaryformat,
125 $context->id, 'course', 'section', $section->id);
126 $sectioncontents = array();
128 //for each module of the section
129 foreach ($modinfo->sections[$section->section] as $cmid) { //matching /course/lib.php:print_section() logic
130 $cm = $modinfo->cms[$cmid];
132 // stop here if the module is not visible to the user
133 if (!$cm->uservisible) {
134 continue;
137 $module = array();
139 //common info (for people being able to see the module or availability dates)
140 $module['id'] = $cm->id;
141 $module['name'] = format_string($cm->name, true);
142 $module['modname'] = $cm->modname;
143 $module['modplural'] = $cm->modplural;
144 $module['modicon'] = $cm->get_icon_url()->out(false);
145 $module['indent'] = $cm->indent;
147 $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
149 if (!empty($cm->showdescription)) {
150 $module['description'] = $cm->get_content();
153 //url of the module
154 $url = $cm->get_url();
155 if ($url) { //labels don't have url
156 $module['url'] = $cm->get_url()->out();
159 $canviewhidden = has_capability('moodle/course:viewhiddenactivities',
160 get_context_instance(CONTEXT_MODULE, $cm->id));
161 //user that can view hidden module should know about the visibility
162 $module['visible'] = $cm->visible;
164 //availability date (also send to user who can see hidden module when the showavailabilyt is ON)
165 if ($canupdatecourse or ($CFG->enableavailability && $canviewhidden && $cm->showavailability)) {
166 $module['availablefrom'] = $cm->availablefrom;
167 $module['availableuntil'] = $cm->availableuntil;
170 $baseurl = 'webservice/pluginfile.php';
172 //call $modulename_export_contents
173 //(each module callback take care about checking the capabilities)
174 require_once($CFG->dirroot . '/mod/' . $cm->modname . '/lib.php');
175 $getcontentfunction = $cm->modname.'_export_contents';
176 if (function_exists($getcontentfunction)) {
177 if ($contents = $getcontentfunction($cm, $baseurl)) {
178 $module['contents'] = $contents;
182 //assign result to $sectioncontents
183 $sectioncontents[] = $module;
186 $sectionvalues['modules'] = $sectioncontents;
188 // assign result to $coursecontents
189 $coursecontents[] = $sectionvalues;
192 return $coursecontents;
196 * Returns description of method result value
198 * @return external_description
199 * @since Moodle 2.2
201 public static function get_course_contents_returns() {
202 return new external_multiple_structure(
203 new external_single_structure(
204 array(
205 'id' => new external_value(PARAM_INT, 'Section ID'),
206 'name' => new external_value(PARAM_TEXT, 'Section name'),
207 'visible' => new external_value(PARAM_INT, 'is the section visible', VALUE_OPTIONAL),
208 'summary' => new external_value(PARAM_RAW, 'Section description'),
209 'summaryformat' => new external_format_value('summary'),
210 'modules' => new external_multiple_structure(
211 new external_single_structure(
212 array(
213 'id' => new external_value(PARAM_INT, 'activity id'),
214 'url' => new external_value(PARAM_URL, 'activity url', VALUE_OPTIONAL),
215 'name' => new external_value(PARAM_RAW, 'activity module name'),
216 'description' => new external_value(PARAM_RAW, 'activity description', VALUE_OPTIONAL),
217 'visible' => new external_value(PARAM_INT, 'is the module visible', VALUE_OPTIONAL),
218 'modicon' => new external_value(PARAM_URL, 'activity icon url'),
219 'modname' => new external_value(PARAM_PLUGIN, 'activity module type'),
220 'modplural' => new external_value(PARAM_TEXT, 'activity module plural name'),
221 'availablefrom' => new external_value(PARAM_INT, 'module availability start date', VALUE_OPTIONAL),
222 'availableuntil' => new external_value(PARAM_INT, 'module availability en date', VALUE_OPTIONAL),
223 'indent' => new external_value(PARAM_INT, 'number of identation in the site'),
224 'contents' => new external_multiple_structure(
225 new external_single_structure(
226 array(
227 // content info
228 'type'=> new external_value(PARAM_TEXT, 'a file or a folder or external link'),
229 'filename'=> new external_value(PARAM_FILE, 'filename'),
230 'filepath'=> new external_value(PARAM_PATH, 'filepath'),
231 'filesize'=> new external_value(PARAM_INT, 'filesize'),
232 'fileurl' => new external_value(PARAM_URL, 'downloadable file url', VALUE_OPTIONAL),
233 'content' => new external_value(PARAM_RAW, 'Raw content, will be used when type is content', VALUE_OPTIONAL),
234 'timecreated' => new external_value(PARAM_INT, 'Time created'),
235 'timemodified' => new external_value(PARAM_INT, 'Time modified'),
236 'sortorder' => new external_value(PARAM_INT, 'Content sort order'),
238 // copyright related info
239 'userid' => new external_value(PARAM_INT, 'User who added this content to moodle'),
240 'author' => new external_value(PARAM_TEXT, 'Content owner'),
241 'license' => new external_value(PARAM_TEXT, 'Content license'),
243 ), VALUE_DEFAULT, array()
246 ), 'list of module'
254 * Returns description of method parameters
256 * @return external_function_parameters
257 * @since Moodle 2.3
259 public static function get_courses_parameters() {
260 return new external_function_parameters(
261 array('options' => new external_single_structure(
262 array('ids' => new external_multiple_structure(
263 new external_value(PARAM_INT, 'Course id')
264 , 'List of course id. If empty return all courses
265 except front page course.',
266 VALUE_OPTIONAL)
267 ), 'options - operator OR is used', VALUE_DEFAULT, array())
273 * Get courses
275 * @param array $options It contains an array (list of ids)
276 * @return array
277 * @since Moodle 2.2
279 public static function get_courses($options = array()) {
280 global $CFG, $DB;
281 require_once($CFG->dirroot . "/course/lib.php");
283 //validate parameter
284 $params = self::validate_parameters(self::get_courses_parameters(),
285 array('options' => $options));
287 //retrieve courses
288 if (!array_key_exists('ids', $params['options'])
289 or empty($params['options']['ids'])) {
290 $courses = $DB->get_records('course');
291 } else {
292 $courses = $DB->get_records_list('course', 'id', $params['options']['ids']);
295 //create return value
296 $coursesinfo = array();
297 foreach ($courses as $course) {
299 // now security checks
300 $context = get_context_instance(CONTEXT_COURSE, $course->id);
301 try {
302 self::validate_context($context);
303 } catch (Exception $e) {
304 $exceptionparam = new stdClass();
305 $exceptionparam->message = $e->getMessage();
306 $exceptionparam->courseid = $course->id;
307 throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
309 require_capability('moodle/course:view', $context);
311 $courseinfo = array();
312 $courseinfo['id'] = $course->id;
313 $courseinfo['fullname'] = $course->fullname;
314 $courseinfo['shortname'] = $course->shortname;
315 $courseinfo['categoryid'] = $course->category;
316 list($courseinfo['summary'], $courseinfo['summaryformat']) =
317 external_format_text($course->summary, $course->summaryformat, $context->id, 'course', 'summary', 0);
318 $courseinfo['format'] = $course->format;
319 $courseinfo['startdate'] = $course->startdate;
320 $courseinfo['numsections'] = $course->numsections;
322 //some field should be returned only if the user has update permission
323 $courseadmin = has_capability('moodle/course:update', $context);
324 if ($courseadmin) {
325 $courseinfo['categorysortorder'] = $course->sortorder;
326 $courseinfo['idnumber'] = $course->idnumber;
327 $courseinfo['showgrades'] = $course->showgrades;
328 $courseinfo['showreports'] = $course->showreports;
329 $courseinfo['newsitems'] = $course->newsitems;
330 $courseinfo['visible'] = $course->visible;
331 $courseinfo['maxbytes'] = $course->maxbytes;
332 $courseinfo['hiddensections'] = $course->hiddensections;
333 $courseinfo['groupmode'] = $course->groupmode;
334 $courseinfo['groupmodeforce'] = $course->groupmodeforce;
335 $courseinfo['defaultgroupingid'] = $course->defaultgroupingid;
336 $courseinfo['lang'] = $course->lang;
337 $courseinfo['timecreated'] = $course->timecreated;
338 $courseinfo['timemodified'] = $course->timemodified;
339 $courseinfo['forcetheme'] = $course->theme;
340 $courseinfo['enablecompletion'] = $course->enablecompletion;
341 $courseinfo['completionstartonenrol'] = $course->completionstartonenrol;
342 $courseinfo['completionnotify'] = $course->completionnotify;
345 if ($courseadmin or $course->visible
346 or has_capability('moodle/course:viewhiddencourses', $context)) {
347 $coursesinfo[] = $courseinfo;
351 return $coursesinfo;
355 * Returns description of method result value
357 * @return external_description
358 * @since Moodle 2.2
360 public static function get_courses_returns() {
361 return new external_multiple_structure(
362 new external_single_structure(
363 array(
364 'id' => new external_value(PARAM_INT, 'course id'),
365 'shortname' => new external_value(PARAM_TEXT, 'course short name'),
366 'categoryid' => new external_value(PARAM_INT, 'category id'),
367 'categorysortorder' => new external_value(PARAM_INT,
368 'sort order into the category', VALUE_OPTIONAL),
369 'fullname' => new external_value(PARAM_TEXT, 'full name'),
370 'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
371 'summary' => new external_value(PARAM_RAW, 'summary'),
372 'summaryformat' => new external_format_value('summary'),
373 'format' => new external_value(PARAM_PLUGIN,
374 'course format: weeks, topics, social, site,..'),
375 'showgrades' => new external_value(PARAM_INT,
376 '1 if grades are shown, otherwise 0', VALUE_OPTIONAL),
377 'newsitems' => new external_value(PARAM_INT,
378 'number of recent items appearing on the course page', VALUE_OPTIONAL),
379 'startdate' => new external_value(PARAM_INT,
380 'timestamp when the course start'),
381 'numsections' => new external_value(PARAM_INT, 'number of weeks/topics'),
382 'maxbytes' => new external_value(PARAM_INT,
383 'largest size of file that can be uploaded into the course',
384 VALUE_OPTIONAL),
385 'showreports' => new external_value(PARAM_INT,
386 'are activity report shown (yes = 1, no =0)', VALUE_OPTIONAL),
387 'visible' => new external_value(PARAM_INT,
388 '1: available to student, 0:not available', VALUE_OPTIONAL),
389 'hiddensections' => new external_value(PARAM_INT,
390 'How the hidden sections in the course are displayed to students',
391 VALUE_OPTIONAL),
392 'groupmode' => new external_value(PARAM_INT, 'no group, separate, visible',
393 VALUE_OPTIONAL),
394 'groupmodeforce' => new external_value(PARAM_INT, '1: yes, 0: no',
395 VALUE_OPTIONAL),
396 'defaultgroupingid' => new external_value(PARAM_INT, 'default grouping id',
397 VALUE_OPTIONAL),
398 'timecreated' => new external_value(PARAM_INT,
399 'timestamp when the course have been created', VALUE_OPTIONAL),
400 'timemodified' => new external_value(PARAM_INT,
401 'timestamp when the course have been modified', VALUE_OPTIONAL),
402 'enablecompletion' => new external_value(PARAM_INT,
403 'Enabled, control via completion and activity settings. Disbaled,
404 not shown in activity settings.',
405 VALUE_OPTIONAL),
406 'completionstartonenrol' => new external_value(PARAM_INT,
407 '1: begin tracking a student\'s progress in course completion
408 after course enrolment. 0: does not',
409 VALUE_OPTIONAL),
410 'completionnotify' => new external_value(PARAM_INT,
411 '1: yes 0: no', VALUE_OPTIONAL),
412 'lang' => new external_value(PARAM_SAFEDIR,
413 'forced course language', VALUE_OPTIONAL),
414 'forcetheme' => new external_value(PARAM_PLUGIN,
415 'name of the force theme', VALUE_OPTIONAL),
416 ), 'course'
422 * Returns description of method parameters
424 * @return external_function_parameters
425 * @since Moodle 2.2
427 public static function create_courses_parameters() {
428 $courseconfig = get_config('moodlecourse'); //needed for many default values
429 return new external_function_parameters(
430 array(
431 'courses' => new external_multiple_structure(
432 new external_single_structure(
433 array(
434 'fullname' => new external_value(PARAM_TEXT, 'full name'),
435 'shortname' => new external_value(PARAM_TEXT, 'course short name'),
436 'categoryid' => new external_value(PARAM_INT, 'category id'),
437 'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
438 'summary' => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL),
439 'summaryformat' => new external_format_value('summary', VALUE_DEFAULT),
440 'format' => new external_value(PARAM_PLUGIN,
441 'course format: weeks, topics, social, site,..',
442 VALUE_DEFAULT, $courseconfig->format),
443 'showgrades' => new external_value(PARAM_INT,
444 '1 if grades are shown, otherwise 0', VALUE_DEFAULT,
445 $courseconfig->showgrades),
446 'newsitems' => new external_value(PARAM_INT,
447 'number of recent items appearing on the course page',
448 VALUE_DEFAULT, $courseconfig->newsitems),
449 'startdate' => new external_value(PARAM_INT,
450 'timestamp when the course start', VALUE_OPTIONAL),
451 'numsections' => new external_value(PARAM_INT, 'number of weeks/topics',
452 VALUE_DEFAULT, $courseconfig->numsections),
453 'maxbytes' => new external_value(PARAM_INT,
454 'largest size of file that can be uploaded into the course',
455 VALUE_DEFAULT, $courseconfig->maxbytes),
456 'showreports' => new external_value(PARAM_INT,
457 'are activity report shown (yes = 1, no =0)', VALUE_DEFAULT,
458 $courseconfig->showreports),
459 'visible' => new external_value(PARAM_INT,
460 '1: available to student, 0:not available', VALUE_OPTIONAL),
461 'hiddensections' => new external_value(PARAM_INT,
462 'How the hidden sections in the course are displayed to students',
463 VALUE_DEFAULT, $courseconfig->hiddensections),
464 'groupmode' => new external_value(PARAM_INT, 'no group, separate, visible',
465 VALUE_DEFAULT, $courseconfig->groupmode),
466 'groupmodeforce' => new external_value(PARAM_INT, '1: yes, 0: no',
467 VALUE_DEFAULT, $courseconfig->groupmodeforce),
468 'defaultgroupingid' => new external_value(PARAM_INT, 'default grouping id',
469 VALUE_DEFAULT, 0),
470 'enablecompletion' => new external_value(PARAM_INT,
471 'Enabled, control via completion and activity settings. Disabled,
472 not shown in activity settings.',
473 VALUE_OPTIONAL),
474 'completionstartonenrol' => new external_value(PARAM_INT,
475 '1: begin tracking a student\'s progress in course completion after
476 course enrolment. 0: does not',
477 VALUE_OPTIONAL),
478 'completionnotify' => new external_value(PARAM_INT,
479 '1: yes 0: no', VALUE_OPTIONAL),
480 'lang' => new external_value(PARAM_SAFEDIR,
481 'forced course language', VALUE_OPTIONAL),
482 'forcetheme' => new external_value(PARAM_PLUGIN,
483 'name of the force theme', VALUE_OPTIONAL),
485 ), 'courses to create'
492 * Create courses
494 * @param array $courses
495 * @return array courses (id and shortname only)
496 * @since Moodle 2.2
498 public static function create_courses($courses) {
499 global $CFG, $DB;
500 require_once($CFG->dirroot . "/course/lib.php");
501 require_once($CFG->libdir . '/completionlib.php');
503 $params = self::validate_parameters(self::create_courses_parameters(),
504 array('courses' => $courses));
506 $availablethemes = get_plugin_list('theme');
507 $availablelangs = get_string_manager()->get_list_of_translations();
509 $transaction = $DB->start_delegated_transaction();
511 foreach ($params['courses'] as $course) {
513 // Ensure the current user is allowed to run this function
514 $context = get_context_instance(CONTEXT_COURSECAT, $course['categoryid']);
515 try {
516 self::validate_context($context);
517 } catch (Exception $e) {
518 $exceptionparam = new stdClass();
519 $exceptionparam->message = $e->getMessage();
520 $exceptionparam->catid = $course['categoryid'];
521 throw new moodle_exception('errorcatcontextnotvalid', 'webservice', '', $exceptionparam);
523 require_capability('moodle/course:create', $context);
525 // Make sure lang is valid
526 if (array_key_exists('lang', $course) and empty($availablelangs[$course['lang']])) {
527 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'lang');
530 // Make sure theme is valid
531 if (array_key_exists('forcetheme', $course)) {
532 if (!empty($CFG->allowcoursethemes)) {
533 if (empty($availablethemes[$course['forcetheme']])) {
534 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'forcetheme');
535 } else {
536 $course['theme'] = $course['forcetheme'];
541 //force visibility if ws user doesn't have the permission to set it
542 $category = $DB->get_record('course_categories', array('id' => $course['categoryid']));
543 if (!has_capability('moodle/course:visibility', $context)) {
544 $course['visible'] = $category->visible;
547 //set default value for completion
548 $courseconfig = get_config('moodlecourse');
549 if (completion_info::is_enabled_for_site()) {
550 if (!array_key_exists('enablecompletion', $course)) {
551 $course['enablecompletion'] = $courseconfig->enablecompletion;
553 if (!array_key_exists('completionstartonenrol', $course)) {
554 $course['completionstartonenrol'] = $courseconfig->completionstartonenrol;
556 } else {
557 $course['enablecompletion'] = 0;
558 $course['completionstartonenrol'] = 0;
561 $course['category'] = $course['categoryid'];
563 // Summary format.
564 $course['summaryformat'] = external_validate_format($course['summaryformat']);
566 //Note: create_course() core function check shortname, idnumber, category
567 $course['id'] = create_course((object) $course)->id;
569 $resultcourses[] = array('id' => $course['id'], 'shortname' => $course['shortname']);
572 $transaction->allow_commit();
574 return $resultcourses;
578 * Returns description of method result value
580 * @return external_description
581 * @since Moodle 2.2
583 public static function create_courses_returns() {
584 return new external_multiple_structure(
585 new external_single_structure(
586 array(
587 'id' => new external_value(PARAM_INT, 'course id'),
588 'shortname' => new external_value(PARAM_TEXT, 'short name'),
595 * Returns description of method parameters
597 * @return external_function_parameters
598 * @since Moodle 2.2
600 public static function delete_courses_parameters() {
601 return new external_function_parameters(
602 array(
603 'courseids' => new external_multiple_structure(new external_value(PARAM_INT, 'course ID')),
609 * Delete courses
611 * @param array $courseids A list of course ids
612 * @since Moodle 2.2
614 public static function delete_courses($courseids) {
615 global $CFG, $DB;
616 require_once($CFG->dirroot."/course/lib.php");
618 // Parameter validation.
619 $params = self::validate_parameters(self::delete_courses_parameters(), array('courseids'=>$courseids));
621 $transaction = $DB->start_delegated_transaction();
623 foreach ($params['courseids'] as $courseid) {
624 $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
626 // Check if the context is valid.
627 $coursecontext = context_course::instance($course->id);
628 self::validate_context($coursecontext);
630 // Check if the current user has enought permissions.
631 if (!can_delete_course($courseid)) {
632 throw new moodle_exception('cannotdeletecategorycourse', 'error',
633 '', format_string($course->fullname)." (id: $courseid)");
636 delete_course($course, false);
639 $transaction->allow_commit();
641 return null;
645 * Returns description of method result value
647 * @return external_description
648 * @since Moodle 2.2
650 public static function delete_courses_returns() {
651 return null;
655 * Returns description of method parameters
657 * @return external_function_parameters
658 * @since Moodle 2.3
660 public static function duplicate_course_parameters() {
661 return new external_function_parameters(
662 array(
663 'courseid' => new external_value(PARAM_INT, 'course to duplicate id'),
664 'fullname' => new external_value(PARAM_TEXT, 'duplicated course full name'),
665 'shortname' => new external_value(PARAM_TEXT, 'duplicated course short name'),
666 'categoryid' => new external_value(PARAM_INT, 'duplicated course category parent'),
667 'visible' => new external_value(PARAM_INT, 'duplicated course visible, default to yes', VALUE_DEFAULT, 1),
668 'options' => new external_multiple_structure(
669 new external_single_structure(
670 array(
671 'name' => new external_value(PARAM_ALPHAEXT, 'The backup option name:
672 "activities" (int) Include course activites (default to 1 that is equal to yes),
673 "blocks" (int) Include course blocks (default to 1 that is equal to yes),
674 "filters" (int) Include course filters (default to 1 that is equal to yes),
675 "users" (int) Include users (default to 0 that is equal to no),
676 "role_assignments" (int) Include role assignments (default to 0 that is equal to no),
677 "comments" (int) Include user comments (default to 0 that is equal to no),
678 "completion_information" (int) Include user course completion information (default to 0 that is equal to no),
679 "logs" (int) Include course logs (default to 0 that is equal to no),
680 "histories" (int) Include histories (default to 0 that is equal to no)'
682 'value' => new external_value(PARAM_RAW, 'the value for the option 1 (yes) or 0 (no)'
685 ), VALUE_DEFAULT, array()
692 * Duplicate a course
694 * @param int $courseid
695 * @param string $fullname Duplicated course fullname
696 * @param string $shortname Duplicated course shortname
697 * @param int $categoryid Duplicated course parent category id
698 * @param int $visible Duplicated course availability
699 * @param array $options List of backup options
700 * @return array New course info
701 * @since Moodle 2.3
703 public static function duplicate_course($courseid, $fullname, $shortname, $categoryid, $visible = 1, $options = array()) {
704 global $CFG, $USER, $DB;
705 require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
706 require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
708 // Parameter validation.
709 $params = self::validate_parameters(
710 self::duplicate_course_parameters(),
711 array(
712 'courseid' => $courseid,
713 'fullname' => $fullname,
714 'shortname' => $shortname,
715 'categoryid' => $categoryid,
716 'visible' => $visible,
717 'options' => $options
721 // Context validation.
723 if (! ($course = $DB->get_record('course', array('id'=>$params['courseid'])))) {
724 throw new moodle_exception('invalidcourseid', 'error');
727 // Category where duplicated course is going to be created.
728 $categorycontext = context_coursecat::instance($params['categoryid']);
729 self::validate_context($categorycontext);
731 // Course to be duplicated.
732 $coursecontext = context_course::instance($course->id);
733 self::validate_context($coursecontext);
735 $backupdefaults = array(
736 'activities' => 1,
737 'blocks' => 1,
738 'filters' => 1,
739 'users' => 0,
740 'role_assignments' => 0,
741 'comments' => 0,
742 'completion_information' => 0,
743 'logs' => 0,
744 'histories' => 0
747 $backupsettings = array();
748 // Check for backup and restore options.
749 if (!empty($params['options'])) {
750 foreach ($params['options'] as $option) {
752 // Strict check for a correct value (allways 1 or 0, true or false).
753 $value = clean_param($option['value'], PARAM_INT);
755 if ($value !== 0 and $value !== 1) {
756 throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
759 if (!isset($backupdefaults[$option['name']])) {
760 throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
763 $backupsettings[$option['name']] = $value;
767 // Capability checking.
769 // The backup controller check for this currently, this may be redundant.
770 require_capability('moodle/course:create', $categorycontext);
771 require_capability('moodle/restore:restorecourse', $categorycontext);
772 require_capability('moodle/backup:backupcourse', $coursecontext);
774 if (!empty($backupsettings['users'])) {
775 require_capability('moodle/backup:userinfo', $coursecontext);
776 require_capability('moodle/restore:userinfo', $categorycontext);
779 // Check if the shortname is used.
780 if ($foundcourses = $DB->get_records('course', array('shortname'=>$shortname))) {
781 foreach ($foundcourses as $foundcourse) {
782 $foundcoursenames[] = $foundcourse->fullname;
785 $foundcoursenamestring = implode(',', $foundcoursenames);
786 throw new moodle_exception('shortnametaken', '', '', $foundcoursenamestring);
789 // Backup the course.
791 $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE,
792 backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id);
794 foreach ($backupsettings as $name => $value) {
795 $bc->get_plan()->get_setting($name)->set_value($value);
798 $backupid = $bc->get_backupid();
799 $backupbasepath = $bc->get_plan()->get_basepath();
801 $bc->execute_plan();
802 $results = $bc->get_results();
803 $file = $results['backup_destination'];
805 $bc->destroy();
807 // Restore the backup immediately.
809 // Check if we need to unzip the file because the backup temp dir does not contains backup files.
810 if (!file_exists($backupbasepath . "/moodle_backup.xml")) {
811 $file->extract_to_pathname(get_file_packer(), $backupbasepath);
814 // Create new course.
815 $newcourseid = restore_dbops::create_new_course($params['fullname'], $params['shortname'], $params['categoryid']);
817 $rc = new restore_controller($backupid, $newcourseid,
818 backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id, backup::TARGET_NEW_COURSE);
820 foreach ($backupsettings as $name => $value) {
821 $setting = $rc->get_plan()->get_setting($name);
822 if ($setting->get_status() == backup_setting::NOT_LOCKED) {
823 $setting->set_value($value);
827 if (!$rc->execute_precheck()) {
828 $precheckresults = $rc->get_precheck_results();
829 if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
830 if (empty($CFG->keeptempdirectoriesonbackup)) {
831 fulldelete($backupbasepath);
834 $errorinfo = '';
836 foreach ($precheckresults['errors'] as $error) {
837 $errorinfo .= $error;
840 if (array_key_exists('warnings', $precheckresults)) {
841 foreach ($precheckresults['warnings'] as $warning) {
842 $errorinfo .= $warning;
846 throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo);
850 $rc->execute_plan();
851 $rc->destroy();
853 $course = $DB->get_record('course', array('id' => $newcourseid), '*', MUST_EXIST);
854 $course->fullname = $params['fullname'];
855 $course->shortname = $params['shortname'];
856 $course->visible = $params['visible'];
858 // Set shortname and fullname back.
859 $DB->update_record('course', $course);
861 if (empty($CFG->keeptempdirectoriesonbackup)) {
862 fulldelete($backupbasepath);
865 // Delete the course backup file created by this WebService. Originally located in the course backups area.
866 $file->delete();
868 return array('id' => $course->id, 'shortname' => $course->shortname);
872 * Returns description of method result value
874 * @return external_description
875 * @since Moodle 2.3
877 public static function duplicate_course_returns() {
878 return new external_single_structure(
879 array(
880 'id' => new external_value(PARAM_INT, 'course id'),
881 'shortname' => new external_value(PARAM_TEXT, 'short name'),
887 * Returns description of method parameters
889 * @return external_function_parameters
890 * @since Moodle 2.3
892 public static function get_categories_parameters() {
893 return new external_function_parameters(
894 array(
895 'criteria' => new external_multiple_structure(
896 new external_single_structure(
897 array(
898 'key' => new external_value(PARAM_ALPHA,
899 'The category column to search, expected keys (value format) are:'.
900 '"id" (int) the category id,'.
901 '"name" (string) the category name,'.
902 '"parent" (int) the parent category id,'.
903 '"idnumber" (string) category idnumber'.
904 ' - user must have \'moodle/category:manage\' to search on idnumber,'.
905 '"visible" (int) whether the returned categories must be visible or hidden. If the key is not passed,
906 then the function return all categories that the user can see.'.
907 ' - user must have \'moodle/category:manage\' or \'moodle/category:viewhiddencategories\' to search on visible,'.
908 '"theme" (string) only return the categories having this theme'.
909 ' - user must have \'moodle/category:manage\' to search on theme'),
910 'value' => new external_value(PARAM_RAW, 'the value to match')
912 ), 'criteria', VALUE_DEFAULT, array()
914 'addsubcategories' => new external_value(PARAM_BOOL, 'return the sub categories infos
915 (1 - default) otherwise only the category info (0)', VALUE_DEFAULT, 1)
921 * Get categories
923 * @param array $criteria Criteria to match the results
924 * @param booln $addsubcategories obtain only the category (false) or its subcategories (true - default)
925 * @return array list of categories
926 * @since Moodle 2.3
928 public static function get_categories($criteria = array(), $addsubcategories = true) {
929 global $CFG, $DB;
930 require_once($CFG->dirroot . "/course/lib.php");
932 // Validate parameters.
933 $params = self::validate_parameters(self::get_categories_parameters(),
934 array('criteria' => $criteria, 'addsubcategories' => $addsubcategories));
936 // Retrieve the categories.
937 $categories = array();
938 if (!empty($params['criteria'])) {
940 $conditions = array();
941 $wheres = array();
942 foreach ($params['criteria'] as $crit) {
943 $key = trim($crit['key']);
945 // Trying to avoid duplicate keys.
946 if (!isset($conditions[$key])) {
948 $context = context_system::instance();
949 $value = null;
950 switch ($key) {
951 case 'id':
952 $value = clean_param($crit['value'], PARAM_INT);
953 break;
955 case 'idnumber':
956 if (has_capability('moodle/category:manage', $context)) {
957 $value = clean_param($crit['value'], PARAM_RAW);
958 } else {
959 // We must throw an exception.
960 // Otherwise the dev client would think no idnumber exists.
961 throw new moodle_exception('criteriaerror',
962 'webservice', '', null,
963 'You don\'t have the permissions to search on the "idnumber" field.');
965 break;
967 case 'name':
968 $value = clean_param($crit['value'], PARAM_TEXT);
969 break;
971 case 'parent':
972 $value = clean_param($crit['value'], PARAM_INT);
973 break;
975 case 'visible':
976 if (has_capability('moodle/category:manage', $context)
977 or has_capability('moodle/category:viewhiddencategories',
978 context_system::instance())) {
979 $value = clean_param($crit['value'], PARAM_INT);
980 } else {
981 throw new moodle_exception('criteriaerror',
982 'webservice', '', null,
983 'You don\'t have the permissions to search on the "visible" field.');
985 break;
987 case 'theme':
988 if (has_capability('moodle/category:manage', $context)) {
989 $value = clean_param($crit['value'], PARAM_THEME);
990 } else {
991 throw new moodle_exception('criteriaerror',
992 'webservice', '', null,
993 'You don\'t have the permissions to search on the "theme" field.');
995 break;
997 default:
998 throw new moodle_exception('criteriaerror',
999 'webservice', '', null,
1000 'You can not search on this criteria: ' . $key);
1003 if (isset($value)) {
1004 $conditions[$key] = $crit['value'];
1005 $wheres[] = $key . " = :" . $key;
1010 if (!empty($wheres)) {
1011 $wheres = implode(" AND ", $wheres);
1013 $categories = $DB->get_records_select('course_categories', $wheres, $conditions);
1015 // Retrieve its sub subcategories (all levels).
1016 if ($categories and !empty($params['addsubcategories'])) {
1017 $newcategories = array();
1019 // Check if we required visible/theme checks.
1020 $additionalselect = '';
1021 $additionalparams = array();
1022 if (isset($conditions['visible'])) {
1023 $additionalselect .= ' AND visible = :visible';
1024 $additionalparams['visible'] = $conditions['visible'];
1026 if (isset($conditions['theme'])) {
1027 $additionalselect .= ' AND theme= :theme';
1028 $additionalparams['theme'] = $conditions['theme'];
1031 foreach ($categories as $category) {
1032 $sqlselect = $DB->sql_like('path', ':path') . $additionalselect;
1033 $sqlparams = array('path' => $category->path.'/%') + $additionalparams; // It will NOT include the specified category.
1034 $subcategories = $DB->get_records_select('course_categories', $sqlselect, $sqlparams);
1035 $newcategories = $newcategories + $subcategories; // Both arrays have integer as keys.
1037 $categories = $categories + $newcategories;
1041 } else {
1042 // Retrieve all categories in the database.
1043 $categories = $DB->get_records('course_categories');
1046 // The not returned categories. key => category id, value => reason of exclusion.
1047 $excludedcats = array();
1049 // The returned categories.
1050 $categoriesinfo = array();
1052 // We need to sort the categories by path.
1053 // The parent cats need to be checked by the algo first.
1054 usort($categories, "core_course_external::compare_categories_by_path");
1056 foreach ($categories as $category) {
1058 // Check if the category is a child of an excluded category, if yes exclude it too (excluded => do not return).
1059 $parents = explode('/', $category->path);
1060 unset($parents[0]); // First key is always empty because path start with / => /1/2/4.
1061 foreach ($parents as $parentid) {
1062 // Note: when the parent exclusion was due to the context,
1063 // the sub category could still be returned.
1064 if (isset($excludedcats[$parentid]) and $excludedcats[$parentid] != 'context') {
1065 $excludedcats[$category->id] = 'parent';
1069 // Check category depth is <= maxdepth (do not check for user who can manage categories).
1070 if ((!empty($CFG->maxcategorydepth) && count($parents) > $CFG->maxcategorydepth)
1071 and !has_capability('moodle/category:manage', $context)) {
1072 $excludedcats[$category->id] = 'depth';
1075 // Check the user can use the category context.
1076 $context = context_coursecat::instance($category->id);
1077 try {
1078 self::validate_context($context);
1079 } catch (Exception $e) {
1080 $excludedcats[$category->id] = 'context';
1082 // If it was the requested category then throw an exception.
1083 if (isset($params['categoryid']) && $category->id == $params['categoryid']) {
1084 $exceptionparam = new stdClass();
1085 $exceptionparam->message = $e->getMessage();
1086 $exceptionparam->catid = $category->id;
1087 throw new moodle_exception('errorcatcontextnotvalid', 'webservice', '', $exceptionparam);
1091 // Return the category information.
1092 if (!isset($excludedcats[$category->id])) {
1094 // Final check to see if the category is visible to the user.
1095 if ($category->visible
1096 or has_capability('moodle/category:viewhiddencategories', context_system::instance())
1097 or has_capability('moodle/category:manage', $context)) {
1099 $categoryinfo = array();
1100 $categoryinfo['id'] = $category->id;
1101 $categoryinfo['name'] = $category->name;
1102 list($categoryinfo['description'], $categoryinfo['descriptionformat']) =
1103 external_format_text($category->description, $category->descriptionformat,
1104 $context->id, 'coursecat', 'description', null);
1105 $categoryinfo['parent'] = $category->parent;
1106 $categoryinfo['sortorder'] = $category->sortorder;
1107 $categoryinfo['coursecount'] = $category->coursecount;
1108 $categoryinfo['depth'] = $category->depth;
1109 $categoryinfo['path'] = $category->path;
1111 // Some fields only returned for admin.
1112 if (has_capability('moodle/category:manage', $context)) {
1113 $categoryinfo['idnumber'] = $category->idnumber;
1114 $categoryinfo['visible'] = $category->visible;
1115 $categoryinfo['visibleold'] = $category->visibleold;
1116 $categoryinfo['timemodified'] = $category->timemodified;
1117 $categoryinfo['theme'] = $category->theme;
1120 $categoriesinfo[] = $categoryinfo;
1121 } else {
1122 $excludedcats[$category->id] = 'visibility';
1127 // Sorting the resulting array so it looks a bit better for the client developer.
1128 usort($categoriesinfo, "core_course_external::compare_categories_by_sortorder");
1130 return $categoriesinfo;
1134 * Sort categories array by path
1135 * private function: only used by get_categories
1137 * @param array $category1
1138 * @param array $category2
1139 * @return int result of strcmp
1140 * @since Moodle 2.3
1142 private static function compare_categories_by_path($category1, $category2) {
1143 return strcmp($category1->path, $category2->path);
1147 * Sort categories array by sortorder
1148 * private function: only used by get_categories
1150 * @param array $category1
1151 * @param array $category2
1152 * @return int result of strcmp
1153 * @since Moodle 2.3
1155 private static function compare_categories_by_sortorder($category1, $category2) {
1156 return strcmp($category1['sortorder'], $category2['sortorder']);
1160 * Returns description of method result value
1162 * @return external_description
1163 * @since Moodle 2.3
1165 public static function get_categories_returns() {
1166 return new external_multiple_structure(
1167 new external_single_structure(
1168 array(
1169 'id' => new external_value(PARAM_INT, 'category id'),
1170 'name' => new external_value(PARAM_TEXT, 'category name'),
1171 'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
1172 'description' => new external_value(PARAM_RAW, 'category description'),
1173 'descriptionformat' => new external_format_value('description'),
1174 'parent' => new external_value(PARAM_INT, 'parent category id'),
1175 'sortorder' => new external_value(PARAM_INT, 'category sorting order'),
1176 'coursecount' => new external_value(PARAM_INT, 'number of courses in this category'),
1177 'visible' => new external_value(PARAM_INT, '1: available, 0:not available', VALUE_OPTIONAL),
1178 'visibleold' => new external_value(PARAM_INT, '1: available, 0:not available', VALUE_OPTIONAL),
1179 'timemodified' => new external_value(PARAM_INT, 'timestamp', VALUE_OPTIONAL),
1180 'depth' => new external_value(PARAM_INT, 'category depth'),
1181 'path' => new external_value(PARAM_TEXT, 'category path'),
1182 'theme' => new external_value(PARAM_THEME, 'category theme', VALUE_OPTIONAL),
1183 ), 'List of categories'
1189 * Returns description of method parameters
1191 * @return external_function_parameters
1192 * @since Moodle 2.3
1194 public static function create_categories_parameters() {
1195 return new external_function_parameters(
1196 array(
1197 'categories' => new external_multiple_structure(
1198 new external_single_structure(
1199 array(
1200 'name' => new external_value(PARAM_TEXT, 'new category name'),
1201 'parent' => new external_value(PARAM_INT,
1202 'the parent category id inside which the new category will be created
1203 - set to 0 for a root category',
1204 VALUE_DEFAULT, 0),
1205 'idnumber' => new external_value(PARAM_RAW,
1206 'the new category idnumber', VALUE_OPTIONAL),
1207 'description' => new external_value(PARAM_RAW,
1208 'the new category description', VALUE_OPTIONAL),
1209 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
1210 'theme' => new external_value(PARAM_THEME,
1211 'the new category theme. This option must be enabled on moodle',
1212 VALUE_OPTIONAL),
1221 * Create categories
1223 * @param array $categories - see create_categories_parameters() for the array structure
1224 * @return array - see create_categories_returns() for the array structure
1225 * @since Moodle 2.3
1227 public static function create_categories($categories) {
1228 global $CFG, $DB;
1229 require_once($CFG->dirroot . "/course/lib.php");
1231 $params = self::validate_parameters(self::create_categories_parameters(),
1232 array('categories' => $categories));
1234 $transaction = $DB->start_delegated_transaction();
1236 $createdcategories = array();
1237 foreach ($params['categories'] as $category) {
1238 if ($category['parent']) {
1239 if (!$DB->record_exists('course_categories', array('id' => $category['parent']))) {
1240 throw new moodle_exception('unknowcategory');
1242 $context = context_coursecat::instance($category['parent']);
1243 } else {
1244 $context = context_system::instance();
1246 self::validate_context($context);
1247 require_capability('moodle/category:manage', $context);
1249 // Check name.
1250 if (textlib::strlen($category['name'])>255) {
1251 throw new moodle_exception('categorytoolong');
1254 $newcategory = new stdClass();
1255 $newcategory->name = $category['name'];
1256 $newcategory->parent = $category['parent'];
1257 // Format the description.
1258 if (!empty($category['description'])) {
1259 $newcategory->description = $category['description'];
1261 $newcategory->descriptionformat = external_validate_format($category['descriptionformat']);
1262 if (isset($category['theme']) and !empty($CFG->allowcategorythemes)) {
1263 $newcategory->theme = $category['theme'];
1265 // Check id number.
1266 if (!empty($category['idnumber'])) { // Same as in course/editcategory_form.php .
1267 if (textlib::strlen($category['idnumber'])>100) {
1268 throw new moodle_exception('idnumbertoolong');
1270 if ($existing = $DB->get_record('course_categories', array('idnumber' => $category['idnumber']))) {
1271 if ($existing->id) {
1272 throw new moodle_exception('idnumbertaken');
1275 $newcategory->idnumber = $category['idnumber'];
1278 $newcategory = create_course_category($newcategory);
1279 // Populate special fields.
1280 fix_course_sortorder();
1282 $createdcategories[] = array('id' => $newcategory->id, 'name' => $newcategory->name);
1285 $transaction->allow_commit();
1287 return $createdcategories;
1291 * Returns description of method parameters
1293 * @return external_function_parameters
1294 * @since Moodle 2.3
1296 public static function create_categories_returns() {
1297 return new external_multiple_structure(
1298 new external_single_structure(
1299 array(
1300 'id' => new external_value(PARAM_INT, 'new category id'),
1301 'name' => new external_value(PARAM_TEXT, 'new category name'),
1308 * Returns description of method parameters
1310 * @return external_function_parameters
1311 * @since Moodle 2.3
1313 public static function update_categories_parameters() {
1314 return new external_function_parameters(
1315 array(
1316 'categories' => new external_multiple_structure(
1317 new external_single_structure(
1318 array(
1319 'id' => new external_value(PARAM_INT, 'course id'),
1320 'name' => new external_value(PARAM_TEXT, 'category name', VALUE_OPTIONAL),
1321 'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
1322 'parent' => new external_value(PARAM_INT, 'parent category id', VALUE_OPTIONAL),
1323 'description' => new external_value(PARAM_RAW, 'category description', VALUE_OPTIONAL),
1324 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
1325 'theme' => new external_value(PARAM_THEME,
1326 'the category theme. This option must be enabled on moodle', VALUE_OPTIONAL),
1335 * Update categories
1337 * @param array $categories The list of categories to update
1338 * @return null
1339 * @since Moodle 2.3
1341 public static function update_categories($categories) {
1342 global $CFG, $DB;
1343 require_once($CFG->dirroot . "/course/lib.php");
1345 // Validate parameters.
1346 $params = self::validate_parameters(self::update_categories_parameters(), array('categories' => $categories));
1348 $transaction = $DB->start_delegated_transaction();
1350 foreach ($params['categories'] as $cat) {
1351 if (!$category = $DB->get_record('course_categories', array('id' => $cat['id']))) {
1352 throw new moodle_exception('unknowcategory');
1355 $categorycontext = context_coursecat::instance($cat['id']);
1356 self::validate_context($categorycontext);
1357 require_capability('moodle/category:manage', $categorycontext);
1359 if (!empty($cat['name'])) {
1360 if (textlib::strlen($cat['name'])>255) {
1361 throw new moodle_exception('categorytoolong');
1363 $category->name = $cat['name'];
1365 if (!empty($cat['idnumber'])) {
1366 if (textlib::strlen($cat['idnumber'])>100) {
1367 throw new moodle_exception('idnumbertoolong');
1369 $category->idnumber = $cat['idnumber'];
1371 if (!empty($cat['description'])) {
1372 $category->description = $cat['description'];
1373 $category->descriptionformat = external_validate_format($cat['descriptionformat']);
1375 if (!empty($cat['theme'])) {
1376 $category->theme = $cat['theme'];
1378 if (!empty($cat['parent']) && ($category->parent != $cat['parent'])) {
1379 // First check if parent exists.
1380 if (!$parent_cat = $DB->get_record('course_categories', array('id' => $cat['parent']))) {
1381 throw new moodle_exception('unknowcategory');
1383 // Then check if we have capability.
1384 self::validate_context(get_category_or_system_context((int)$cat['parent']));
1385 require_capability('moodle/category:manage', get_category_or_system_context((int)$cat['parent']));
1386 // Finally move the category.
1387 move_category($category, $parent_cat);
1388 $category->parent = $cat['parent'];
1389 // Get updated path by move_category().
1390 $category->path = $DB->get_field('course_categories', 'path',
1391 array('id' => $category->id));
1393 $DB->update_record('course_categories', $category);
1396 $transaction->allow_commit();
1400 * Returns description of method result value
1402 * @return external_description
1403 * @since Moodle 2.3
1405 public static function update_categories_returns() {
1406 return null;
1410 * Returns description of method parameters
1412 * @return external_function_parameters
1413 * @since Moodle 2.3
1415 public static function delete_categories_parameters() {
1416 return new external_function_parameters(
1417 array(
1418 'categories' => new external_multiple_structure(
1419 new external_single_structure(
1420 array(
1421 'id' => new external_value(PARAM_INT, 'category id to delete'),
1422 'newparent' => new external_value(PARAM_INT,
1423 'the parent category to move the contents to, if specified', VALUE_OPTIONAL),
1424 'recursive' => new external_value(PARAM_BOOL, '1: recursively delete all contents inside this
1425 category, 0 (default): move contents to newparent or current parent category (except if parent is root)', VALUE_DEFAULT, 0)
1434 * Delete categories
1436 * @param array $categories A list of category ids
1437 * @return array
1438 * @since Moodle 2.3
1440 public static function delete_categories($categories) {
1441 global $CFG, $DB;
1442 require_once($CFG->dirroot . "/course/lib.php");
1444 // Validate parameters.
1445 $params = self::validate_parameters(self::delete_categories_parameters(), array('categories' => $categories));
1447 $transaction = $DB->start_delegated_transaction();
1449 foreach ($params['categories'] as $category) {
1450 if (!$deletecat = $DB->get_record('course_categories', array('id' => $category['id']))) {
1451 throw new moodle_exception('unknowcategory');
1453 $context = context_coursecat::instance($deletecat->id);
1454 require_capability('moodle/category:manage', $context);
1455 self::validate_context($context);
1456 self::validate_context(get_category_or_system_context($deletecat->parent));
1458 if ($category['recursive']) {
1459 // If recursive was specified, then we recursively delete the category's contents.
1460 category_delete_full($deletecat, false);
1461 } else {
1462 // In this situation, we don't delete the category's contents, we either move it to newparent or parent.
1463 // If the parent is the root, moving is not supported (because a course must always be inside a category).
1464 // We must move to an existing category.
1465 if (!empty($category['newparent'])) {
1466 if (!$DB->record_exists('course_categories', array('id' => $category['newparent']))) {
1467 throw new moodle_exception('unknowcategory');
1469 $newparent = $category['newparent'];
1470 } else {
1471 $newparent = $deletecat->parent;
1474 // This operation is not allowed. We must move contents to an existing category.
1475 if ($newparent == 0) {
1476 throw new moodle_exception('movecatcontentstoroot');
1479 $parentcontext = get_category_or_system_context($newparent);
1480 require_capability('moodle/category:manage', $parentcontext);
1481 self::validate_context($parentcontext);
1482 category_delete_move($deletecat, $newparent, false);
1486 $transaction->allow_commit();
1490 * Returns description of method parameters
1492 * @return external_function_parameters
1493 * @since Moodle 2.3
1495 public static function delete_categories_returns() {
1496 return null;
1502 * Deprecated course external functions
1504 * @package core_course
1505 * @copyright 2009 Petr Skodak
1506 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1507 * @since Moodle 2.0
1508 * @deprecated Moodle 2.2 MDL-29106 - Please do not use this class any more.
1509 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1510 * @see core_course_external
1512 class moodle_course_external extends external_api {
1515 * Returns description of method parameters
1517 * @return external_function_parameters
1518 * @since Moodle 2.0
1519 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1520 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1521 * @see core_course_external::get_courses_parameters()
1523 public static function get_courses_parameters() {
1524 return core_course_external::get_courses_parameters();
1528 * Get courses
1530 * @param array $options
1531 * @return array
1532 * @since Moodle 2.0
1533 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1534 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1535 * @see core_course_external::get_courses()
1537 public static function get_courses($options) {
1538 return core_course_external::get_courses($options);
1542 * Returns description of method result value
1544 * @return external_description
1545 * @since Moodle 2.0
1546 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1547 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1548 * @see core_course_external::get_courses_returns()
1550 public static function get_courses_returns() {
1551 return core_course_external::get_courses_returns();
1555 * Returns description of method parameters
1557 * @return external_function_parameters
1558 * @since Moodle 2.0
1559 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1560 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1561 * @see core_course_external::create_courses_parameters()
1563 public static function create_courses_parameters() {
1564 return core_course_external::create_courses_parameters();
1568 * Create courses
1570 * @param array $courses
1571 * @return array courses (id and shortname only)
1572 * @since Moodle 2.0
1573 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1574 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1575 * @see core_course_external::create_courses()
1577 public static function create_courses($courses) {
1578 return core_course_external::create_courses($courses);
1582 * Returns description of method result value
1584 * @return external_description
1585 * @since Moodle 2.0
1586 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1587 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1588 * @see core_course_external::create_courses_returns()
1590 public static function create_courses_returns() {
1591 return core_course_external::create_courses_returns();