Merge branch 'w27_MDL-39754_m23_evn26' of https://github.com/skodak/moodle into MOODL...
[moodle.git] / course / externallib.php
blob1a7920174b6eb691094705c7410d85b3785733c8
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 $modinfosections = $modinfo->get_sections();
112 foreach ($sections as $key => $section) {
114 $showsection = (has_capability('moodle/course:viewhiddensections', $context) or $section->visible or !$course->hiddensections);
115 if (!$showsection) {
116 continue;
119 // reset $sectioncontents
120 $sectionvalues = array();
121 $sectionvalues['id'] = $section->id;
122 $sectionvalues['name'] = get_section_name($course, $section);
123 $sectionvalues['visible'] = $section->visible;
124 list($sectionvalues['summary'], $sectionvalues['summaryformat']) =
125 external_format_text($section->summary, $section->summaryformat,
126 $context->id, 'course', 'section', $section->id);
127 $sectioncontents = array();
129 //for each module of the section
130 if (!empty($modinfosections[$section->section])) {
131 foreach ($modinfosections[$section->section] as $cmid) {
132 $cm = $modinfo->cms[$cmid];
134 // stop here if the module is not visible to the user
135 if (!$cm->uservisible) {
136 continue;
139 $module = array();
141 //common info (for people being able to see the module or availability dates)
142 $module['id'] = $cm->id;
143 $module['name'] = format_string($cm->name, true);
144 $module['modname'] = $cm->modname;
145 $module['modplural'] = $cm->modplural;
146 $module['modicon'] = $cm->get_icon_url()->out(false);
147 $module['indent'] = $cm->indent;
149 $modcontext = context_module::instance($cm->id);
151 if (!empty($cm->showdescription)) {
152 $module['description'] = $cm->get_content();
155 //url of the module
156 $url = $cm->get_url();
157 if ($url) { //labels don't have url
158 $module['url'] = $cm->get_url()->out();
161 $canviewhidden = has_capability('moodle/course:viewhiddenactivities',
162 context_module::instance($cm->id));
163 //user that can view hidden module should know about the visibility
164 $module['visible'] = $cm->visible;
166 //availability date (also send to user who can see hidden module when the showavailabilyt is ON)
167 if ($canupdatecourse or ($CFG->enableavailability && $canviewhidden && $cm->showavailability)) {
168 $module['availablefrom'] = $cm->availablefrom;
169 $module['availableuntil'] = $cm->availableuntil;
172 $baseurl = 'webservice/pluginfile.php';
174 //call $modulename_export_contents
175 //(each module callback take care about checking the capabilities)
176 require_once($CFG->dirroot . '/mod/' . $cm->modname . '/lib.php');
177 $getcontentfunction = $cm->modname.'_export_contents';
178 if (function_exists($getcontentfunction)) {
179 if ($contents = $getcontentfunction($cm, $baseurl)) {
180 $module['contents'] = $contents;
184 //assign result to $sectioncontents
185 $sectioncontents[] = $module;
189 $sectionvalues['modules'] = $sectioncontents;
191 // assign result to $coursecontents
192 $coursecontents[] = $sectionvalues;
195 return $coursecontents;
199 * Returns description of method result value
201 * @return external_description
202 * @since Moodle 2.2
204 public static function get_course_contents_returns() {
205 return new external_multiple_structure(
206 new external_single_structure(
207 array(
208 'id' => new external_value(PARAM_INT, 'Section ID'),
209 'name' => new external_value(PARAM_TEXT, 'Section name'),
210 'visible' => new external_value(PARAM_INT, 'is the section visible', VALUE_OPTIONAL),
211 'summary' => new external_value(PARAM_RAW, 'Section description'),
212 'summaryformat' => new external_format_value('summary'),
213 'modules' => new external_multiple_structure(
214 new external_single_structure(
215 array(
216 'id' => new external_value(PARAM_INT, 'activity id'),
217 'url' => new external_value(PARAM_URL, 'activity url', VALUE_OPTIONAL),
218 'name' => new external_value(PARAM_RAW, 'activity module name'),
219 'description' => new external_value(PARAM_RAW, 'activity description', VALUE_OPTIONAL),
220 'visible' => new external_value(PARAM_INT, 'is the module visible', VALUE_OPTIONAL),
221 'modicon' => new external_value(PARAM_URL, 'activity icon url'),
222 'modname' => new external_value(PARAM_PLUGIN, 'activity module type'),
223 'modplural' => new external_value(PARAM_TEXT, 'activity module plural name'),
224 'availablefrom' => new external_value(PARAM_INT, 'module availability start date', VALUE_OPTIONAL),
225 'availableuntil' => new external_value(PARAM_INT, 'module availability en date', VALUE_OPTIONAL),
226 'indent' => new external_value(PARAM_INT, 'number of identation in the site'),
227 'contents' => new external_multiple_structure(
228 new external_single_structure(
229 array(
230 // content info
231 'type'=> new external_value(PARAM_TEXT, 'a file or a folder or external link'),
232 'filename'=> new external_value(PARAM_FILE, 'filename'),
233 'filepath'=> new external_value(PARAM_PATH, 'filepath'),
234 'filesize'=> new external_value(PARAM_INT, 'filesize'),
235 'fileurl' => new external_value(PARAM_URL, 'downloadable file url', VALUE_OPTIONAL),
236 'content' => new external_value(PARAM_RAW, 'Raw content, will be used when type is content', VALUE_OPTIONAL),
237 'timecreated' => new external_value(PARAM_INT, 'Time created'),
238 'timemodified' => new external_value(PARAM_INT, 'Time modified'),
239 'sortorder' => new external_value(PARAM_INT, 'Content sort order'),
241 // copyright related info
242 'userid' => new external_value(PARAM_INT, 'User who added this content to moodle'),
243 'author' => new external_value(PARAM_TEXT, 'Content owner'),
244 'license' => new external_value(PARAM_TEXT, 'Content license'),
246 ), VALUE_DEFAULT, array()
249 ), 'list of module'
257 * Returns description of method parameters
259 * @return external_function_parameters
260 * @since Moodle 2.3
262 public static function get_courses_parameters() {
263 return new external_function_parameters(
264 array('options' => new external_single_structure(
265 array('ids' => new external_multiple_structure(
266 new external_value(PARAM_INT, 'Course id')
267 , 'List of course id. If empty return all courses
268 except front page course.',
269 VALUE_OPTIONAL)
270 ), 'options - operator OR is used', VALUE_DEFAULT, array())
276 * Get courses
278 * @param array $options It contains an array (list of ids)
279 * @return array
280 * @since Moodle 2.2
282 public static function get_courses($options = array()) {
283 global $CFG, $DB;
284 require_once($CFG->dirroot . "/course/lib.php");
286 //validate parameter
287 $params = self::validate_parameters(self::get_courses_parameters(),
288 array('options' => $options));
290 //retrieve courses
291 if (!array_key_exists('ids', $params['options'])
292 or empty($params['options']['ids'])) {
293 $courses = $DB->get_records('course');
294 } else {
295 $courses = $DB->get_records_list('course', 'id', $params['options']['ids']);
298 //create return value
299 $coursesinfo = array();
300 foreach ($courses as $course) {
302 // now security checks
303 $context = get_context_instance(CONTEXT_COURSE, $course->id);
304 try {
305 self::validate_context($context);
306 } catch (Exception $e) {
307 $exceptionparam = new stdClass();
308 $exceptionparam->message = $e->getMessage();
309 $exceptionparam->courseid = $course->id;
310 throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
312 require_capability('moodle/course:view', $context);
314 $courseinfo = array();
315 $courseinfo['id'] = $course->id;
316 $courseinfo['fullname'] = $course->fullname;
317 $courseinfo['shortname'] = $course->shortname;
318 $courseinfo['categoryid'] = $course->category;
319 list($courseinfo['summary'], $courseinfo['summaryformat']) =
320 external_format_text($course->summary, $course->summaryformat, $context->id, 'course', 'summary', 0);
321 $courseinfo['format'] = $course->format;
322 $courseinfo['startdate'] = $course->startdate;
323 $courseinfo['numsections'] = $course->numsections;
325 //some field should be returned only if the user has update permission
326 $courseadmin = has_capability('moodle/course:update', $context);
327 if ($courseadmin) {
328 $courseinfo['categorysortorder'] = $course->sortorder;
329 $courseinfo['idnumber'] = $course->idnumber;
330 $courseinfo['showgrades'] = $course->showgrades;
331 $courseinfo['showreports'] = $course->showreports;
332 $courseinfo['newsitems'] = $course->newsitems;
333 $courseinfo['visible'] = $course->visible;
334 $courseinfo['maxbytes'] = $course->maxbytes;
335 $courseinfo['hiddensections'] = $course->hiddensections;
336 $courseinfo['groupmode'] = $course->groupmode;
337 $courseinfo['groupmodeforce'] = $course->groupmodeforce;
338 $courseinfo['defaultgroupingid'] = $course->defaultgroupingid;
339 $courseinfo['lang'] = $course->lang;
340 $courseinfo['timecreated'] = $course->timecreated;
341 $courseinfo['timemodified'] = $course->timemodified;
342 $courseinfo['forcetheme'] = $course->theme;
343 $courseinfo['enablecompletion'] = $course->enablecompletion;
344 $courseinfo['completionstartonenrol'] = $course->completionstartonenrol;
345 $courseinfo['completionnotify'] = $course->completionnotify;
348 if ($courseadmin or $course->visible
349 or has_capability('moodle/course:viewhiddencourses', $context)) {
350 $coursesinfo[] = $courseinfo;
354 return $coursesinfo;
358 * Returns description of method result value
360 * @return external_description
361 * @since Moodle 2.2
363 public static function get_courses_returns() {
364 return new external_multiple_structure(
365 new external_single_structure(
366 array(
367 'id' => new external_value(PARAM_INT, 'course id'),
368 'shortname' => new external_value(PARAM_TEXT, 'course short name'),
369 'categoryid' => new external_value(PARAM_INT, 'category id'),
370 'categorysortorder' => new external_value(PARAM_INT,
371 'sort order into the category', VALUE_OPTIONAL),
372 'fullname' => new external_value(PARAM_TEXT, 'full name'),
373 'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
374 'summary' => new external_value(PARAM_RAW, 'summary'),
375 'summaryformat' => new external_format_value('summary'),
376 'format' => new external_value(PARAM_PLUGIN,
377 'course format: weeks, topics, social, site,..'),
378 'showgrades' => new external_value(PARAM_INT,
379 '1 if grades are shown, otherwise 0', VALUE_OPTIONAL),
380 'newsitems' => new external_value(PARAM_INT,
381 'number of recent items appearing on the course page', VALUE_OPTIONAL),
382 'startdate' => new external_value(PARAM_INT,
383 'timestamp when the course start'),
384 'numsections' => new external_value(PARAM_INT, 'number of weeks/topics'),
385 'maxbytes' => new external_value(PARAM_INT,
386 'largest size of file that can be uploaded into the course',
387 VALUE_OPTIONAL),
388 'showreports' => new external_value(PARAM_INT,
389 'are activity report shown (yes = 1, no =0)', VALUE_OPTIONAL),
390 'visible' => new external_value(PARAM_INT,
391 '1: available to student, 0:not available', VALUE_OPTIONAL),
392 'hiddensections' => new external_value(PARAM_INT,
393 'How the hidden sections in the course are displayed to students',
394 VALUE_OPTIONAL),
395 'groupmode' => new external_value(PARAM_INT, 'no group, separate, visible',
396 VALUE_OPTIONAL),
397 'groupmodeforce' => new external_value(PARAM_INT, '1: yes, 0: no',
398 VALUE_OPTIONAL),
399 'defaultgroupingid' => new external_value(PARAM_INT, 'default grouping id',
400 VALUE_OPTIONAL),
401 'timecreated' => new external_value(PARAM_INT,
402 'timestamp when the course have been created', VALUE_OPTIONAL),
403 'timemodified' => new external_value(PARAM_INT,
404 'timestamp when the course have been modified', VALUE_OPTIONAL),
405 'enablecompletion' => new external_value(PARAM_INT,
406 'Enabled, control via completion and activity settings. Disbaled,
407 not shown in activity settings.',
408 VALUE_OPTIONAL),
409 'completionstartonenrol' => new external_value(PARAM_INT,
410 '1: begin tracking a student\'s progress in course completion
411 after course enrolment. 0: does not',
412 VALUE_OPTIONAL),
413 'completionnotify' => new external_value(PARAM_INT,
414 '1: yes 0: no', VALUE_OPTIONAL),
415 'lang' => new external_value(PARAM_SAFEDIR,
416 'forced course language', VALUE_OPTIONAL),
417 'forcetheme' => new external_value(PARAM_PLUGIN,
418 'name of the force theme', VALUE_OPTIONAL),
419 ), 'course'
425 * Returns description of method parameters
427 * @return external_function_parameters
428 * @since Moodle 2.2
430 public static function create_courses_parameters() {
431 $courseconfig = get_config('moodlecourse'); //needed for many default values
432 return new external_function_parameters(
433 array(
434 'courses' => new external_multiple_structure(
435 new external_single_structure(
436 array(
437 'fullname' => new external_value(PARAM_TEXT, 'full name'),
438 'shortname' => new external_value(PARAM_TEXT, 'course short name'),
439 'categoryid' => new external_value(PARAM_INT, 'category id'),
440 'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
441 'summary' => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL),
442 'summaryformat' => new external_format_value('summary', VALUE_DEFAULT),
443 'format' => new external_value(PARAM_PLUGIN,
444 'course format: weeks, topics, social, site,..',
445 VALUE_DEFAULT, $courseconfig->format),
446 'showgrades' => new external_value(PARAM_INT,
447 '1 if grades are shown, otherwise 0', VALUE_DEFAULT,
448 $courseconfig->showgrades),
449 'newsitems' => new external_value(PARAM_INT,
450 'number of recent items appearing on the course page',
451 VALUE_DEFAULT, $courseconfig->newsitems),
452 'startdate' => new external_value(PARAM_INT,
453 'timestamp when the course start', VALUE_OPTIONAL),
454 'numsections' => new external_value(PARAM_INT, 'number of weeks/topics',
455 VALUE_DEFAULT, $courseconfig->numsections),
456 'maxbytes' => new external_value(PARAM_INT,
457 'largest size of file that can be uploaded into the course',
458 VALUE_DEFAULT, $courseconfig->maxbytes),
459 'showreports' => new external_value(PARAM_INT,
460 'are activity report shown (yes = 1, no =0)', VALUE_DEFAULT,
461 $courseconfig->showreports),
462 'visible' => new external_value(PARAM_INT,
463 '1: available to student, 0:not available', VALUE_OPTIONAL),
464 'hiddensections' => new external_value(PARAM_INT,
465 'How the hidden sections in the course are displayed to students',
466 VALUE_DEFAULT, $courseconfig->hiddensections),
467 'groupmode' => new external_value(PARAM_INT, 'no group, separate, visible',
468 VALUE_DEFAULT, $courseconfig->groupmode),
469 'groupmodeforce' => new external_value(PARAM_INT, '1: yes, 0: no',
470 VALUE_DEFAULT, $courseconfig->groupmodeforce),
471 'defaultgroupingid' => new external_value(PARAM_INT, 'default grouping id',
472 VALUE_DEFAULT, 0),
473 'enablecompletion' => new external_value(PARAM_INT,
474 'Enabled, control via completion and activity settings. Disabled,
475 not shown in activity settings.',
476 VALUE_OPTIONAL),
477 'completionstartonenrol' => new external_value(PARAM_INT,
478 '1: begin tracking a student\'s progress in course completion after
479 course enrolment. 0: does not',
480 VALUE_OPTIONAL),
481 'completionnotify' => new external_value(PARAM_INT,
482 '1: yes 0: no', VALUE_OPTIONAL),
483 'lang' => new external_value(PARAM_SAFEDIR,
484 'forced course language', VALUE_OPTIONAL),
485 'forcetheme' => new external_value(PARAM_PLUGIN,
486 'name of the force theme', VALUE_OPTIONAL),
488 ), 'courses to create'
495 * Create courses
497 * @param array $courses
498 * @return array courses (id and shortname only)
499 * @since Moodle 2.2
501 public static function create_courses($courses) {
502 global $CFG, $DB;
503 require_once($CFG->dirroot . "/course/lib.php");
504 require_once($CFG->libdir . '/completionlib.php');
506 $params = self::validate_parameters(self::create_courses_parameters(),
507 array('courses' => $courses));
509 $availablethemes = get_plugin_list('theme');
510 $availablelangs = get_string_manager()->get_list_of_translations();
512 $transaction = $DB->start_delegated_transaction();
514 foreach ($params['courses'] as $course) {
516 // Ensure the current user is allowed to run this function
517 $context = get_context_instance(CONTEXT_COURSECAT, $course['categoryid']);
518 try {
519 self::validate_context($context);
520 } catch (Exception $e) {
521 $exceptionparam = new stdClass();
522 $exceptionparam->message = $e->getMessage();
523 $exceptionparam->catid = $course['categoryid'];
524 throw new moodle_exception('errorcatcontextnotvalid', 'webservice', '', $exceptionparam);
526 require_capability('moodle/course:create', $context);
528 // Make sure lang is valid
529 if (array_key_exists('lang', $course) and empty($availablelangs[$course['lang']])) {
530 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'lang');
533 // Make sure theme is valid
534 if (array_key_exists('forcetheme', $course)) {
535 if (!empty($CFG->allowcoursethemes)) {
536 if (empty($availablethemes[$course['forcetheme']])) {
537 throw new moodle_exception('errorinvalidparam', 'webservice', '', 'forcetheme');
538 } else {
539 $course['theme'] = $course['forcetheme'];
544 //force visibility if ws user doesn't have the permission to set it
545 $category = $DB->get_record('course_categories', array('id' => $course['categoryid']));
546 if (!has_capability('moodle/course:visibility', $context)) {
547 $course['visible'] = $category->visible;
550 //set default value for completion
551 $courseconfig = get_config('moodlecourse');
552 if (completion_info::is_enabled_for_site()) {
553 if (!array_key_exists('enablecompletion', $course)) {
554 $course['enablecompletion'] = $courseconfig->enablecompletion;
556 if (!array_key_exists('completionstartonenrol', $course)) {
557 $course['completionstartonenrol'] = $courseconfig->completionstartonenrol;
559 } else {
560 $course['enablecompletion'] = 0;
561 $course['completionstartonenrol'] = 0;
564 $course['category'] = $course['categoryid'];
566 // Summary format.
567 $course['summaryformat'] = external_validate_format($course['summaryformat']);
569 //Note: create_course() core function check shortname, idnumber, category
570 $course['id'] = create_course((object) $course)->id;
572 $resultcourses[] = array('id' => $course['id'], 'shortname' => $course['shortname']);
575 $transaction->allow_commit();
577 return $resultcourses;
581 * Returns description of method result value
583 * @return external_description
584 * @since Moodle 2.2
586 public static function create_courses_returns() {
587 return new external_multiple_structure(
588 new external_single_structure(
589 array(
590 'id' => new external_value(PARAM_INT, 'course id'),
591 'shortname' => new external_value(PARAM_TEXT, 'short name'),
598 * Returns description of method parameters
600 * @return external_function_parameters
601 * @since Moodle 2.2
603 public static function delete_courses_parameters() {
604 return new external_function_parameters(
605 array(
606 'courseids' => new external_multiple_structure(new external_value(PARAM_INT, 'course ID')),
612 * Delete courses
614 * @param array $courseids A list of course ids
615 * @since Moodle 2.2
617 public static function delete_courses($courseids) {
618 global $CFG, $DB;
619 require_once($CFG->dirroot."/course/lib.php");
621 // Parameter validation.
622 $params = self::validate_parameters(self::delete_courses_parameters(), array('courseids'=>$courseids));
624 $transaction = $DB->start_delegated_transaction();
626 foreach ($params['courseids'] as $courseid) {
627 $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
629 // Check if the context is valid.
630 $coursecontext = context_course::instance($course->id);
631 self::validate_context($coursecontext);
633 // Check if the current user has enought permissions.
634 if (!can_delete_course($courseid)) {
635 throw new moodle_exception('cannotdeletecategorycourse', 'error',
636 '', format_string($course->fullname)." (id: $courseid)");
639 delete_course($course, false);
642 $transaction->allow_commit();
644 return null;
648 * Returns description of method result value
650 * @return external_description
651 * @since Moodle 2.2
653 public static function delete_courses_returns() {
654 return null;
658 * Returns description of method parameters
660 * @return external_function_parameters
661 * @since Moodle 2.3
663 public static function duplicate_course_parameters() {
664 return new external_function_parameters(
665 array(
666 'courseid' => new external_value(PARAM_INT, 'course to duplicate id'),
667 'fullname' => new external_value(PARAM_TEXT, 'duplicated course full name'),
668 'shortname' => new external_value(PARAM_TEXT, 'duplicated course short name'),
669 'categoryid' => new external_value(PARAM_INT, 'duplicated course category parent'),
670 'visible' => new external_value(PARAM_INT, 'duplicated course visible, default to yes', VALUE_DEFAULT, 1),
671 'options' => new external_multiple_structure(
672 new external_single_structure(
673 array(
674 'name' => new external_value(PARAM_ALPHAEXT, 'The backup option name:
675 "activities" (int) Include course activites (default to 1 that is equal to yes),
676 "blocks" (int) Include course blocks (default to 1 that is equal to yes),
677 "filters" (int) Include course filters (default to 1 that is equal to yes),
678 "users" (int) Include users (default to 0 that is equal to no),
679 "role_assignments" (int) Include role assignments (default to 0 that is equal to no),
680 "comments" (int) Include user comments (default to 0 that is equal to no),
681 "userscompletion" (int) Include user course completion information (default to 0 that is equal to no),
682 "logs" (int) Include course logs (default to 0 that is equal to no),
683 "grade_histories" (int) Include histories (default to 0 that is equal to no)'
685 'value' => new external_value(PARAM_RAW, 'the value for the option 1 (yes) or 0 (no)'
688 ), VALUE_DEFAULT, array()
695 * Duplicate a course
697 * @param int $courseid
698 * @param string $fullname Duplicated course fullname
699 * @param string $shortname Duplicated course shortname
700 * @param int $categoryid Duplicated course parent category id
701 * @param int $visible Duplicated course availability
702 * @param array $options List of backup options
703 * @return array New course info
704 * @since Moodle 2.3
706 public static function duplicate_course($courseid, $fullname, $shortname, $categoryid, $visible = 1, $options = array()) {
707 global $CFG, $USER, $DB;
708 require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
709 require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
711 // Parameter validation.
712 $params = self::validate_parameters(
713 self::duplicate_course_parameters(),
714 array(
715 'courseid' => $courseid,
716 'fullname' => $fullname,
717 'shortname' => $shortname,
718 'categoryid' => $categoryid,
719 'visible' => $visible,
720 'options' => $options
724 // Context validation.
726 if (! ($course = $DB->get_record('course', array('id'=>$params['courseid'])))) {
727 throw new moodle_exception('invalidcourseid', 'error');
730 // Category where duplicated course is going to be created.
731 $categorycontext = context_coursecat::instance($params['categoryid']);
732 self::validate_context($categorycontext);
734 // Course to be duplicated.
735 $coursecontext = context_course::instance($course->id);
736 self::validate_context($coursecontext);
738 $backupdefaults = array(
739 'activities' => 1,
740 'blocks' => 1,
741 'filters' => 1,
742 'users' => 0,
743 'role_assignments' => 0,
744 'comments' => 0,
745 'userscompletion' => 0,
746 'logs' => 0,
747 'grade_histories' => 0
750 $backupsettings = array();
751 // Check for backup and restore options.
752 if (!empty($params['options'])) {
753 foreach ($params['options'] as $option) {
755 // Strict check for a correct value (allways 1 or 0, true or false).
756 $value = clean_param($option['value'], PARAM_INT);
758 if ($value !== 0 and $value !== 1) {
759 throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
762 if (!isset($backupdefaults[$option['name']])) {
763 throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
766 $backupsettings[$option['name']] = $value;
770 // Capability checking.
772 // The backup controller check for this currently, this may be redundant.
773 require_capability('moodle/course:create', $categorycontext);
774 require_capability('moodle/restore:restorecourse', $categorycontext);
775 require_capability('moodle/backup:backupcourse', $coursecontext);
777 if (!empty($backupsettings['users'])) {
778 require_capability('moodle/backup:userinfo', $coursecontext);
779 require_capability('moodle/restore:userinfo', $categorycontext);
782 // Check if the shortname is used.
783 if ($foundcourses = $DB->get_records('course', array('shortname'=>$shortname))) {
784 foreach ($foundcourses as $foundcourse) {
785 $foundcoursenames[] = $foundcourse->fullname;
788 $foundcoursenamestring = implode(',', $foundcoursenames);
789 throw new moodle_exception('shortnametaken', '', '', $foundcoursenamestring);
792 // Backup the course.
794 $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE,
795 backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id);
797 foreach ($backupsettings as $name => $value) {
798 $bc->get_plan()->get_setting($name)->set_value($value);
801 $backupid = $bc->get_backupid();
802 $backupbasepath = $bc->get_plan()->get_basepath();
804 $bc->execute_plan();
805 $results = $bc->get_results();
806 $file = $results['backup_destination'];
808 $bc->destroy();
810 // Restore the backup immediately.
812 // Check if we need to unzip the file because the backup temp dir does not contains backup files.
813 if (!file_exists($backupbasepath . "/moodle_backup.xml")) {
814 $file->extract_to_pathname(get_file_packer(), $backupbasepath);
817 // Create new course.
818 $newcourseid = restore_dbops::create_new_course($params['fullname'], $params['shortname'], $params['categoryid']);
820 $rc = new restore_controller($backupid, $newcourseid,
821 backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id, backup::TARGET_NEW_COURSE);
823 foreach ($backupsettings as $name => $value) {
824 $setting = $rc->get_plan()->get_setting($name);
825 if ($setting->get_status() == backup_setting::NOT_LOCKED) {
826 $setting->set_value($value);
830 if (!$rc->execute_precheck()) {
831 $precheckresults = $rc->get_precheck_results();
832 if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
833 if (empty($CFG->keeptempdirectoriesonbackup)) {
834 fulldelete($backupbasepath);
837 $errorinfo = '';
839 foreach ($precheckresults['errors'] as $error) {
840 $errorinfo .= $error;
843 if (array_key_exists('warnings', $precheckresults)) {
844 foreach ($precheckresults['warnings'] as $warning) {
845 $errorinfo .= $warning;
849 throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo);
853 $rc->execute_plan();
854 $rc->destroy();
856 $course = $DB->get_record('course', array('id' => $newcourseid), '*', MUST_EXIST);
857 $course->fullname = $params['fullname'];
858 $course->shortname = $params['shortname'];
859 $course->visible = $params['visible'];
861 // Set shortname and fullname back.
862 $DB->update_record('course', $course);
864 if (empty($CFG->keeptempdirectoriesonbackup)) {
865 fulldelete($backupbasepath);
868 // Delete the course backup file created by this WebService. Originally located in the course backups area.
869 $file->delete();
871 return array('id' => $course->id, 'shortname' => $course->shortname);
875 * Returns description of method result value
877 * @return external_description
878 * @since Moodle 2.3
880 public static function duplicate_course_returns() {
881 return new external_single_structure(
882 array(
883 'id' => new external_value(PARAM_INT, 'course id'),
884 'shortname' => new external_value(PARAM_TEXT, 'short name'),
890 * Returns description of method parameters
892 * @return external_function_parameters
893 * @since Moodle 2.3
895 public static function get_categories_parameters() {
896 return new external_function_parameters(
897 array(
898 'criteria' => new external_multiple_structure(
899 new external_single_structure(
900 array(
901 'key' => new external_value(PARAM_ALPHA,
902 'The category column to search, expected keys (value format) are:'.
903 '"id" (int) the category id,'.
904 '"name" (string) the category name,'.
905 '"parent" (int) the parent category id,'.
906 '"idnumber" (string) category idnumber'.
907 ' - user must have \'moodle/category:manage\' to search on idnumber,'.
908 '"visible" (int) whether the returned categories must be visible or hidden. If the key is not passed,
909 then the function return all categories that the user can see.'.
910 ' - user must have \'moodle/category:manage\' or \'moodle/category:viewhiddencategories\' to search on visible,'.
911 '"theme" (string) only return the categories having this theme'.
912 ' - user must have \'moodle/category:manage\' to search on theme'),
913 'value' => new external_value(PARAM_RAW, 'the value to match')
915 ), 'criteria', VALUE_DEFAULT, array()
917 'addsubcategories' => new external_value(PARAM_BOOL, 'return the sub categories infos
918 (1 - default) otherwise only the category info (0)', VALUE_DEFAULT, 1)
924 * Get categories
926 * @param array $criteria Criteria to match the results
927 * @param booln $addsubcategories obtain only the category (false) or its subcategories (true - default)
928 * @return array list of categories
929 * @since Moodle 2.3
931 public static function get_categories($criteria = array(), $addsubcategories = true) {
932 global $CFG, $DB;
933 require_once($CFG->dirroot . "/course/lib.php");
935 // Validate parameters.
936 $params = self::validate_parameters(self::get_categories_parameters(),
937 array('criteria' => $criteria, 'addsubcategories' => $addsubcategories));
939 // Retrieve the categories.
940 $categories = array();
941 if (!empty($params['criteria'])) {
943 $conditions = array();
944 $wheres = array();
945 foreach ($params['criteria'] as $crit) {
946 $key = trim($crit['key']);
948 // Trying to avoid duplicate keys.
949 if (!isset($conditions[$key])) {
951 $context = context_system::instance();
952 $value = null;
953 switch ($key) {
954 case 'id':
955 $value = clean_param($crit['value'], PARAM_INT);
956 break;
958 case 'idnumber':
959 if (has_capability('moodle/category:manage', $context)) {
960 $value = clean_param($crit['value'], PARAM_RAW);
961 } else {
962 // We must throw an exception.
963 // Otherwise the dev client would think no idnumber exists.
964 throw new moodle_exception('criteriaerror',
965 'webservice', '', null,
966 'You don\'t have the permissions to search on the "idnumber" field.');
968 break;
970 case 'name':
971 $value = clean_param($crit['value'], PARAM_TEXT);
972 break;
974 case 'parent':
975 $value = clean_param($crit['value'], PARAM_INT);
976 break;
978 case 'visible':
979 if (has_capability('moodle/category:manage', $context)
980 or has_capability('moodle/category:viewhiddencategories',
981 context_system::instance())) {
982 $value = clean_param($crit['value'], PARAM_INT);
983 } else {
984 throw new moodle_exception('criteriaerror',
985 'webservice', '', null,
986 'You don\'t have the permissions to search on the "visible" field.');
988 break;
990 case 'theme':
991 if (has_capability('moodle/category:manage', $context)) {
992 $value = clean_param($crit['value'], PARAM_THEME);
993 } else {
994 throw new moodle_exception('criteriaerror',
995 'webservice', '', null,
996 'You don\'t have the permissions to search on the "theme" field.');
998 break;
1000 default:
1001 throw new moodle_exception('criteriaerror',
1002 'webservice', '', null,
1003 'You can not search on this criteria: ' . $key);
1006 if (isset($value)) {
1007 $conditions[$key] = $crit['value'];
1008 $wheres[] = $key . " = :" . $key;
1013 if (!empty($wheres)) {
1014 $wheres = implode(" AND ", $wheres);
1016 $categories = $DB->get_records_select('course_categories', $wheres, $conditions);
1018 // Retrieve its sub subcategories (all levels).
1019 if ($categories and !empty($params['addsubcategories'])) {
1020 $newcategories = array();
1022 // Check if we required visible/theme checks.
1023 $additionalselect = '';
1024 $additionalparams = array();
1025 if (isset($conditions['visible'])) {
1026 $additionalselect .= ' AND visible = :visible';
1027 $additionalparams['visible'] = $conditions['visible'];
1029 if (isset($conditions['theme'])) {
1030 $additionalselect .= ' AND theme= :theme';
1031 $additionalparams['theme'] = $conditions['theme'];
1034 foreach ($categories as $category) {
1035 $sqlselect = $DB->sql_like('path', ':path') . $additionalselect;
1036 $sqlparams = array('path' => $category->path.'/%') + $additionalparams; // It will NOT include the specified category.
1037 $subcategories = $DB->get_records_select('course_categories', $sqlselect, $sqlparams);
1038 $newcategories = $newcategories + $subcategories; // Both arrays have integer as keys.
1040 $categories = $categories + $newcategories;
1044 } else {
1045 // Retrieve all categories in the database.
1046 $categories = $DB->get_records('course_categories');
1049 // The not returned categories. key => category id, value => reason of exclusion.
1050 $excludedcats = array();
1052 // The returned categories.
1053 $categoriesinfo = array();
1055 // We need to sort the categories by path.
1056 // The parent cats need to be checked by the algo first.
1057 usort($categories, "core_course_external::compare_categories_by_path");
1059 foreach ($categories as $category) {
1061 // Check if the category is a child of an excluded category, if yes exclude it too (excluded => do not return).
1062 $parents = explode('/', $category->path);
1063 unset($parents[0]); // First key is always empty because path start with / => /1/2/4.
1064 foreach ($parents as $parentid) {
1065 // Note: when the parent exclusion was due to the context,
1066 // the sub category could still be returned.
1067 if (isset($excludedcats[$parentid]) and $excludedcats[$parentid] != 'context') {
1068 $excludedcats[$category->id] = 'parent';
1072 // Check category depth is <= maxdepth (do not check for user who can manage categories).
1073 if ((!empty($CFG->maxcategorydepth) && count($parents) > $CFG->maxcategorydepth)
1074 and !has_capability('moodle/category:manage', $context)) {
1075 $excludedcats[$category->id] = 'depth';
1078 // Check the user can use the category context.
1079 $context = context_coursecat::instance($category->id);
1080 try {
1081 self::validate_context($context);
1082 } catch (Exception $e) {
1083 $excludedcats[$category->id] = 'context';
1085 // If it was the requested category then throw an exception.
1086 if (isset($params['categoryid']) && $category->id == $params['categoryid']) {
1087 $exceptionparam = new stdClass();
1088 $exceptionparam->message = $e->getMessage();
1089 $exceptionparam->catid = $category->id;
1090 throw new moodle_exception('errorcatcontextnotvalid', 'webservice', '', $exceptionparam);
1094 // Return the category information.
1095 if (!isset($excludedcats[$category->id])) {
1097 // Final check to see if the category is visible to the user.
1098 if ($category->visible
1099 or has_capability('moodle/category:viewhiddencategories', context_system::instance())
1100 or has_capability('moodle/category:manage', $context)) {
1102 $categoryinfo = array();
1103 $categoryinfo['id'] = $category->id;
1104 $categoryinfo['name'] = $category->name;
1105 list($categoryinfo['description'], $categoryinfo['descriptionformat']) =
1106 external_format_text($category->description, $category->descriptionformat,
1107 $context->id, 'coursecat', 'description', null);
1108 $categoryinfo['parent'] = $category->parent;
1109 $categoryinfo['sortorder'] = $category->sortorder;
1110 $categoryinfo['coursecount'] = $category->coursecount;
1111 $categoryinfo['depth'] = $category->depth;
1112 $categoryinfo['path'] = $category->path;
1114 // Some fields only returned for admin.
1115 if (has_capability('moodle/category:manage', $context)) {
1116 $categoryinfo['idnumber'] = $category->idnumber;
1117 $categoryinfo['visible'] = $category->visible;
1118 $categoryinfo['visibleold'] = $category->visibleold;
1119 $categoryinfo['timemodified'] = $category->timemodified;
1120 $categoryinfo['theme'] = $category->theme;
1123 $categoriesinfo[] = $categoryinfo;
1124 } else {
1125 $excludedcats[$category->id] = 'visibility';
1130 // Sorting the resulting array so it looks a bit better for the client developer.
1131 usort($categoriesinfo, "core_course_external::compare_categories_by_sortorder");
1133 return $categoriesinfo;
1137 * Sort categories array by path
1138 * private function: only used by get_categories
1140 * @param array $category1
1141 * @param array $category2
1142 * @return int result of strcmp
1143 * @since Moodle 2.3
1145 private static function compare_categories_by_path($category1, $category2) {
1146 return strcmp($category1->path, $category2->path);
1150 * Sort categories array by sortorder
1151 * private function: only used by get_categories
1153 * @param array $category1
1154 * @param array $category2
1155 * @return int result of strcmp
1156 * @since Moodle 2.3
1158 private static function compare_categories_by_sortorder($category1, $category2) {
1159 return strcmp($category1['sortorder'], $category2['sortorder']);
1163 * Returns description of method result value
1165 * @return external_description
1166 * @since Moodle 2.3
1168 public static function get_categories_returns() {
1169 return new external_multiple_structure(
1170 new external_single_structure(
1171 array(
1172 'id' => new external_value(PARAM_INT, 'category id'),
1173 'name' => new external_value(PARAM_TEXT, 'category name'),
1174 'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
1175 'description' => new external_value(PARAM_RAW, 'category description'),
1176 'descriptionformat' => new external_format_value('description'),
1177 'parent' => new external_value(PARAM_INT, 'parent category id'),
1178 'sortorder' => new external_value(PARAM_INT, 'category sorting order'),
1179 'coursecount' => new external_value(PARAM_INT, 'number of courses in this category'),
1180 'visible' => new external_value(PARAM_INT, '1: available, 0:not available', VALUE_OPTIONAL),
1181 'visibleold' => new external_value(PARAM_INT, '1: available, 0:not available', VALUE_OPTIONAL),
1182 'timemodified' => new external_value(PARAM_INT, 'timestamp', VALUE_OPTIONAL),
1183 'depth' => new external_value(PARAM_INT, 'category depth'),
1184 'path' => new external_value(PARAM_TEXT, 'category path'),
1185 'theme' => new external_value(PARAM_THEME, 'category theme', VALUE_OPTIONAL),
1186 ), 'List of categories'
1192 * Returns description of method parameters
1194 * @return external_function_parameters
1195 * @since Moodle 2.3
1197 public static function create_categories_parameters() {
1198 return new external_function_parameters(
1199 array(
1200 'categories' => new external_multiple_structure(
1201 new external_single_structure(
1202 array(
1203 'name' => new external_value(PARAM_TEXT, 'new category name'),
1204 'parent' => new external_value(PARAM_INT,
1205 'the parent category id inside which the new category will be created
1206 - set to 0 for a root category',
1207 VALUE_DEFAULT, 0),
1208 'idnumber' => new external_value(PARAM_RAW,
1209 'the new category idnumber', VALUE_OPTIONAL),
1210 'description' => new external_value(PARAM_RAW,
1211 'the new category description', VALUE_OPTIONAL),
1212 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
1213 'theme' => new external_value(PARAM_THEME,
1214 'the new category theme. This option must be enabled on moodle',
1215 VALUE_OPTIONAL),
1224 * Create categories
1226 * @param array $categories - see create_categories_parameters() for the array structure
1227 * @return array - see create_categories_returns() for the array structure
1228 * @since Moodle 2.3
1230 public static function create_categories($categories) {
1231 global $CFG, $DB;
1232 require_once($CFG->dirroot . "/course/lib.php");
1234 $params = self::validate_parameters(self::create_categories_parameters(),
1235 array('categories' => $categories));
1237 $transaction = $DB->start_delegated_transaction();
1239 $createdcategories = array();
1240 foreach ($params['categories'] as $category) {
1241 if ($category['parent']) {
1242 if (!$DB->record_exists('course_categories', array('id' => $category['parent']))) {
1243 throw new moodle_exception('unknowcategory');
1245 $context = context_coursecat::instance($category['parent']);
1246 } else {
1247 $context = context_system::instance();
1249 self::validate_context($context);
1250 require_capability('moodle/category:manage', $context);
1252 // Check name.
1253 if (textlib::strlen($category['name'])>255) {
1254 throw new moodle_exception('categorytoolong');
1257 $newcategory = new stdClass();
1258 $newcategory->name = $category['name'];
1259 $newcategory->parent = $category['parent'];
1260 // Format the description.
1261 if (!empty($category['description'])) {
1262 $newcategory->description = $category['description'];
1264 $newcategory->descriptionformat = external_validate_format($category['descriptionformat']);
1265 if (isset($category['theme']) and !empty($CFG->allowcategorythemes)) {
1266 $newcategory->theme = $category['theme'];
1268 // Check id number.
1269 if (!empty($category['idnumber'])) { // Same as in course/editcategory_form.php .
1270 if (textlib::strlen($category['idnumber'])>100) {
1271 throw new moodle_exception('idnumbertoolong');
1273 if ($existing = $DB->get_record('course_categories', array('idnumber' => $category['idnumber']))) {
1274 if ($existing->id) {
1275 throw new moodle_exception('idnumbertaken');
1278 $newcategory->idnumber = $category['idnumber'];
1281 $newcategory = create_course_category($newcategory);
1282 // Populate special fields.
1283 fix_course_sortorder();
1285 $createdcategories[] = array('id' => $newcategory->id, 'name' => $newcategory->name);
1288 $transaction->allow_commit();
1290 return $createdcategories;
1294 * Returns description of method parameters
1296 * @return external_function_parameters
1297 * @since Moodle 2.3
1299 public static function create_categories_returns() {
1300 return new external_multiple_structure(
1301 new external_single_structure(
1302 array(
1303 'id' => new external_value(PARAM_INT, 'new category id'),
1304 'name' => new external_value(PARAM_TEXT, 'new category name'),
1311 * Returns description of method parameters
1313 * @return external_function_parameters
1314 * @since Moodle 2.3
1316 public static function update_categories_parameters() {
1317 return new external_function_parameters(
1318 array(
1319 'categories' => new external_multiple_structure(
1320 new external_single_structure(
1321 array(
1322 'id' => new external_value(PARAM_INT, 'course id'),
1323 'name' => new external_value(PARAM_TEXT, 'category name', VALUE_OPTIONAL),
1324 'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
1325 'parent' => new external_value(PARAM_INT, 'parent category id', VALUE_OPTIONAL),
1326 'description' => new external_value(PARAM_RAW, 'category description', VALUE_OPTIONAL),
1327 'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
1328 'theme' => new external_value(PARAM_THEME,
1329 'the category theme. This option must be enabled on moodle', VALUE_OPTIONAL),
1338 * Update categories
1340 * @param array $categories The list of categories to update
1341 * @return null
1342 * @since Moodle 2.3
1344 public static function update_categories($categories) {
1345 global $CFG, $DB;
1346 require_once($CFG->dirroot . "/course/lib.php");
1348 // Validate parameters.
1349 $params = self::validate_parameters(self::update_categories_parameters(), array('categories' => $categories));
1351 $transaction = $DB->start_delegated_transaction();
1353 foreach ($params['categories'] as $cat) {
1354 if (!$category = $DB->get_record('course_categories', array('id' => $cat['id']))) {
1355 throw new moodle_exception('unknowcategory');
1358 $categorycontext = context_coursecat::instance($cat['id']);
1359 self::validate_context($categorycontext);
1360 require_capability('moodle/category:manage', $categorycontext);
1362 if (!empty($cat['name'])) {
1363 if (textlib::strlen($cat['name'])>255) {
1364 throw new moodle_exception('categorytoolong');
1366 $category->name = $cat['name'];
1368 if (!empty($cat['idnumber'])) {
1369 if (textlib::strlen($cat['idnumber'])>100) {
1370 throw new moodle_exception('idnumbertoolong');
1372 $category->idnumber = $cat['idnumber'];
1374 if (!empty($cat['description'])) {
1375 $category->description = $cat['description'];
1376 $category->descriptionformat = external_validate_format($cat['descriptionformat']);
1378 if (!empty($cat['theme'])) {
1379 $category->theme = $cat['theme'];
1381 if (!empty($cat['parent']) && ($category->parent != $cat['parent'])) {
1382 // First check if parent exists.
1383 if (!$parent_cat = $DB->get_record('course_categories', array('id' => $cat['parent']))) {
1384 throw new moodle_exception('unknowcategory');
1386 // Then check if we have capability.
1387 self::validate_context(get_category_or_system_context((int)$cat['parent']));
1388 require_capability('moodle/category:manage', get_category_or_system_context((int)$cat['parent']));
1389 // Finally move the category.
1390 move_category($category, $parent_cat);
1391 $category->parent = $cat['parent'];
1392 // Get updated path by move_category().
1393 $category->path = $DB->get_field('course_categories', 'path',
1394 array('id' => $category->id));
1396 $DB->update_record('course_categories', $category);
1399 $transaction->allow_commit();
1403 * Returns description of method result value
1405 * @return external_description
1406 * @since Moodle 2.3
1408 public static function update_categories_returns() {
1409 return null;
1413 * Returns description of method parameters
1415 * @return external_function_parameters
1416 * @since Moodle 2.3
1418 public static function delete_categories_parameters() {
1419 return new external_function_parameters(
1420 array(
1421 'categories' => new external_multiple_structure(
1422 new external_single_structure(
1423 array(
1424 'id' => new external_value(PARAM_INT, 'category id to delete'),
1425 'newparent' => new external_value(PARAM_INT,
1426 'the parent category to move the contents to, if specified', VALUE_OPTIONAL),
1427 'recursive' => new external_value(PARAM_BOOL, '1: recursively delete all contents inside this
1428 category, 0 (default): move contents to newparent or current parent category (except if parent is root)', VALUE_DEFAULT, 0)
1437 * Delete categories
1439 * @param array $categories A list of category ids
1440 * @return array
1441 * @since Moodle 2.3
1443 public static function delete_categories($categories) {
1444 global $CFG, $DB;
1445 require_once($CFG->dirroot . "/course/lib.php");
1447 // Validate parameters.
1448 $params = self::validate_parameters(self::delete_categories_parameters(), array('categories' => $categories));
1450 $transaction = $DB->start_delegated_transaction();
1452 foreach ($params['categories'] as $category) {
1453 if (!$deletecat = $DB->get_record('course_categories', array('id' => $category['id']))) {
1454 throw new moodle_exception('unknowcategory');
1456 $context = context_coursecat::instance($deletecat->id);
1457 require_capability('moodle/category:manage', $context);
1458 self::validate_context($context);
1459 self::validate_context(get_category_or_system_context($deletecat->parent));
1461 if ($category['recursive']) {
1462 // If recursive was specified, then we recursively delete the category's contents.
1463 category_delete_full($deletecat, false);
1464 } else {
1465 // In this situation, we don't delete the category's contents, we either move it to newparent or parent.
1466 // If the parent is the root, moving is not supported (because a course must always be inside a category).
1467 // We must move to an existing category.
1468 if (!empty($category['newparent'])) {
1469 if (!$DB->record_exists('course_categories', array('id' => $category['newparent']))) {
1470 throw new moodle_exception('unknowcategory');
1472 $newparent = $category['newparent'];
1473 } else {
1474 $newparent = $deletecat->parent;
1477 // This operation is not allowed. We must move contents to an existing category.
1478 if ($newparent == 0) {
1479 throw new moodle_exception('movecatcontentstoroot');
1482 $parentcontext = get_category_or_system_context($newparent);
1483 require_capability('moodle/category:manage', $parentcontext);
1484 self::validate_context($parentcontext);
1485 category_delete_move($deletecat, $newparent, false);
1489 $transaction->allow_commit();
1493 * Returns description of method parameters
1495 * @return external_function_parameters
1496 * @since Moodle 2.3
1498 public static function delete_categories_returns() {
1499 return null;
1505 * Deprecated course external functions
1507 * @package core_course
1508 * @copyright 2009 Petr Skodak
1509 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1510 * @since Moodle 2.0
1511 * @deprecated Moodle 2.2 MDL-29106 - Please do not use this class any more.
1512 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1513 * @see core_course_external
1515 class moodle_course_external extends external_api {
1518 * Returns description of method parameters
1520 * @return external_function_parameters
1521 * @since Moodle 2.0
1522 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1523 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1524 * @see core_course_external::get_courses_parameters()
1526 public static function get_courses_parameters() {
1527 return core_course_external::get_courses_parameters();
1531 * Get courses
1533 * @param array $options
1534 * @return array
1535 * @since Moodle 2.0
1536 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1537 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1538 * @see core_course_external::get_courses()
1540 public static function get_courses($options) {
1541 return core_course_external::get_courses($options);
1545 * Returns description of method result value
1547 * @return external_description
1548 * @since Moodle 2.0
1549 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1550 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1551 * @see core_course_external::get_courses_returns()
1553 public static function get_courses_returns() {
1554 return core_course_external::get_courses_returns();
1558 * Returns description of method parameters
1560 * @return external_function_parameters
1561 * @since Moodle 2.0
1562 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1563 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1564 * @see core_course_external::create_courses_parameters()
1566 public static function create_courses_parameters() {
1567 return core_course_external::create_courses_parameters();
1571 * Create courses
1573 * @param array $courses
1574 * @return array courses (id and shortname only)
1575 * @since Moodle 2.0
1576 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1577 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1578 * @see core_course_external::create_courses()
1580 public static function create_courses($courses) {
1581 return core_course_external::create_courses($courses);
1585 * Returns description of method result value
1587 * @return external_description
1588 * @since Moodle 2.0
1589 * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1590 * @todo MDL-31194 This will be deleted in Moodle 2.5.
1591 * @see core_course_external::create_courses_returns()
1593 public static function create_courses_returns() {
1594 return core_course_external::create_courses_returns();