MDL-42377 backup: fixed incorrect debugging message
[moodle.git] / course / management.php
blob5a22de55d17bb89a1639781fd78867c6fd5e006b
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Course and category management interfaces.
20 * @package core_course
21 * @copyright 2013 Sam Hemelryk
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 require_once('../config.php');
26 require_once($CFG->dirroot.'/lib/coursecatlib.php');
27 require_once($CFG->dirroot.'/course/lib.php');
29 $categoryid = optional_param('categoryid', null, PARAM_INT);
30 $courseid = optional_param('courseid', null, PARAM_INT);
31 $action = optional_param('action', false, PARAM_ALPHA);
32 $page = optional_param('page', 0, PARAM_INT);
33 $perpage = optional_param('perpage', null, PARAM_INT);
34 $viewmode = optional_param('view', 'default', PARAM_ALPHA); // Can be one of default, combined, courses, or categories.
36 // Search related params.
37 $search = optional_param('search', '', PARAM_RAW); // Search words. Shortname, fullname, idnumber and summary get searched.
38 $blocklist = optional_param('blocklist', 0, PARAM_INT); // Find courses containing this block.
39 $modulelist = optional_param('modulelist', '', PARAM_PLUGIN); // Find courses containing the given modules.
41 if (!in_array($viewmode, array('default', 'combined', 'courses', 'categories'))) {
42 $viewmode = 'default';
45 $issearching = ($search !== '' || $blocklist !== 0 || $modulelist !== '');
46 if ($issearching) {
47 $viewmode = 'courses';
50 $url = new moodle_url('/course/management.php');
51 navigation_node::override_active_url($url);
52 $systemcontext = $context = context_system::instance();
53 if ($courseid) {
54 $record = get_course($courseid);
55 $course = new course_in_list($record);
56 $category = coursecat::get($course->category);
57 $categoryid = $category->id;
58 $context = context_coursecat::instance($category->id);
59 $url->param('courseid', $course->id);
60 } else if ($categoryid) {
61 $courseid = null;
62 $course = null;
63 $category = coursecat::get($categoryid);
64 $context = context_coursecat::instance($category->id);
65 $url->param('categoryid', $category->id);
66 } else {
67 $course = null;
68 $courseid = null;
69 $category = null;
70 $categoryid = null;
71 if ($viewmode === 'default') {
72 $viewmode = 'categories';
74 $context = $systemcontext;
77 if ($page !== 0) {
78 $url->param('page', $page);
80 if ($viewmode !== 'default') {
81 $url->param('view', $viewmode);
83 if ($search !== '') {
84 $url->param('search', $search);
86 if ($blocklist !== 0) {
87 $url->param('blocklist', $search);
89 if ($modulelist !== '') {
90 $url->param('modulelist', $search);
93 $title = format_string($SITE->fullname, true, array('context' => $systemcontext));
95 $PAGE->set_context($context);
96 $PAGE->set_url($url);
97 $PAGE->set_pagelayout('admin');
98 $PAGE->set_title($title);
99 $PAGE->set_heading($title);
101 if (!coursecat::has_capability_on_any(array('moodle/category:manage', 'moodle/course:create'))) {
102 // The user isn't able to manage any categories. Lets redirect them to the relevant course/index.php page.
103 $url = new moodle_url('/course/index.php');
104 if ($categoryid) {
105 $url->param('categoryid', $categoryid);
107 redirect($url);
110 // If the user poses any of these capabilities then they will be able to see the admin
111 // tree and the management link within it.
112 // This is the most accurate form of navigation.
113 $capabilities = array(
114 'moodle/site:config',
115 'moodle/backup:backupcourse',
116 'moodle/category:manage',
117 'moodle/course:create',
118 'moodle/site:approvecourse'
120 if ($category && !has_any_capability($capabilities, $systemcontext)) {
121 // If the user doesn't poses any of these system capabilities then we're going to mark the manage link in the settings block
122 // as active, tell the page to ignore the active path and just build what the user would expect.
123 // This will at least give the page some relevant navigation.
124 navigation_node::override_active_url(new moodle_url('/course/management.php', array('categoryid' => $category->id)));
125 $PAGE->set_category_by_id($category->id);
126 $PAGE->navbar->ignore_active(true);
127 $PAGE->navbar->add(get_string('coursemgmt', 'admin'), $PAGE->url->out_omit_querystring());
129 if (!$issearching && $category !== null) {
130 $parents = coursecat::get_many($category->get_parents());
131 $parents[] = $category;
132 foreach ($parents as $parent) {
133 $PAGE->navbar->add(
134 $parent->get_formatted_name(),
135 new moodle_url('/course/management.php', array('categoryid' => $parent->id))
138 if ($course instanceof course_in_list) {
139 // Use the list name so that it matches whats being displayed below.
140 $PAGE->navbar->add($course->get_formatted_name());
144 // This is a system level page that operates on other contexts.
145 require_login();
147 $notificationspass = array();
148 $notificationsfail = array();
150 if ($action !== false && confirm_sesskey()) {
151 // Actions:
152 // - resortcategories : Resort the courses in the given category.
153 // - resortcourses : Resort courses
154 // - showcourse : make a course visible.
155 // - hidecourse : make a course hidden.
156 // - movecourseup : move the selected course up one.
157 // - movecoursedown : move the selected course down.
158 // - showcategory : make a category visible.
159 // - hidecategory : make a category hidden.
160 // - movecategoryup : move category up.
161 // - movecategorydown : move category down.
162 // - deletecategory : delete the category either in full, or moving contents.
163 // - bulkaction : performs bulk actions:
164 // - bulkmovecourses.
165 // - bulkmovecategories.
166 // - bulkresortcategories.
167 $redirectback = false;
168 switch ($action) {
169 case 'resortcategories' :
170 $sort = required_param('resort', PARAM_ALPHA);
171 $cattosort = coursecat::get((int)optional_param('categoryid', 0, PARAM_INT));
172 $redirectback = \core_course\management\helper::action_category_resort_subcategories($cattosort, $sort);
173 break;
174 case 'resortcourses' :
175 // They must have specified a category.
176 required_param('categoryid', PARAM_INT);
177 $sort = required_param('resort', PARAM_ALPHA);
178 \core_course\management\helper::action_category_resort_courses($category, $sort);
179 break;
180 case 'showcourse' :
181 $redirectback = \core_course\management\helper::action_course_show($course);
182 break;
183 case 'hidecourse' :
184 $redirectback = \core_course\management\helper::action_course_hide($course);
185 break;
186 case 'movecourseup' :
187 // They must have specified a category and a course.
188 required_param('categoryid', PARAM_INT);
189 required_param('courseid', PARAM_INT);
190 $redirectback = \core_course\management\helper::action_course_change_sortorder_up_one($course, $category);
191 break;
192 case 'movecoursedown' :
193 // They must have specified a category and a course.
194 required_param('categoryid', PARAM_INT);
195 required_param('courseid', PARAM_INT);
196 $redirectback = \core_course\management\helper::action_course_change_sortorder_down_one($course, $category);
197 break;
198 case 'showcategory' :
199 // They must have specified a category.
200 required_param('categoryid', PARAM_INT);
201 $redirectback = \core_course\management\helper::action_category_show($category);
202 break;
203 case 'hidecategory' :
204 // They must have specified a category.
205 required_param('categoryid', PARAM_INT);
206 $redirectback = \core_course\management\helper::action_category_hide($category);
207 break;
208 case 'movecategoryup' :
209 // They must have specified a category.
210 required_param('categoryid', PARAM_INT);
211 $redirectback = \core_course\management\helper::action_category_change_sortorder_up_one($category);
212 break;
213 case 'movecategorydown' :
214 // They must have specified a category.
215 required_param('categoryid', PARAM_INT);
216 $redirectback = \core_course\management\helper::action_category_change_sortorder_down_one($category);
217 break;
218 case 'deletecategory':
219 // They must have specified a category.
220 required_param('categoryid', PARAM_INT);
221 if (!$category->can_delete()) {
222 throw new moodle_exception('permissiondenied', 'error', '', null, 'coursecat::can_resort');
224 require_once($CFG->dirroot.'/course/delete_category_form.php');
225 $mform = new core_course_deletecategory_form(null, $category);
226 if ($mform->is_cancelled()) {
227 redirect($PAGE->url);
229 // Start output.
230 /* @var core_course_management_renderer|core_renderer $renderer */
231 $renderer = $PAGE->get_renderer('core_course', 'management');
232 echo $renderer->header();
233 echo $renderer->heading(get_string('deletecategory', 'moodle', $category->get_formatted_name()));
235 if ($data = $mform->get_data()) {
236 // The form has been submit handle it.
237 if ($data->fulldelete == 1 && $category->can_delete_full()) {
238 $continueurl = new moodle_url('/course/management.php');
239 if ($category->parent != '0') {
240 $continueurl->param('categoryid', $category->parent);
242 $notification = get_string('coursecategorydeleted', '', $category->get_formatted_name());
243 $deletedcourses = $category->delete_full(true);
244 foreach ($deletedcourses as $course) {
245 echo $renderer->notification(get_string('coursedeleted', '', $course->shortname), 'notifysuccess');
247 echo $renderer->notification($notification, 'notifysuccess');
248 echo $renderer->continue_button($continueurl);
249 } else if ($data->fulldelete == 0 && $category->can_move_content_to($data->newparent)) {
250 $continueurl = new moodle_url('/course/management.php', array('categoryid' => $data->newparent));
251 $category->delete_move($data->newparent, true);
252 echo $renderer->continue_button($continueurl);
253 } else {
254 // Some error in parameters (user is cheating?)
255 $mform->display();
257 } else {
258 // Display the form.
259 $mform->display();
261 // Finish output and exit.
262 echo $renderer->footer();
263 exit();
264 break;
265 case 'bulkaction':
266 $bulkmovecourses = optional_param('bulkmovecourses', false, PARAM_BOOL);
267 $bulkmovecategories = optional_param('bulkmovecategories', false, PARAM_BOOL);
268 $bulkresortcategories = optional_param('bulkresortcategories', false, PARAM_BOOL);
270 if ($bulkmovecourses) {
271 // Move courses out of the current category and into a new category.
272 // They must have specified a category.
273 required_param('categoryid', PARAM_INT);
274 $movetoid = required_param('movecoursesto', PARAM_INT);
275 $courseids = optional_param_array('bc', false, PARAM_INT);
276 if ($courseids === false) {
277 break;
279 $moveto = coursecat::get($movetoid);
280 try {
281 // If this fails we want to catch the exception and report it.
282 $redirectback = \core_course\management\helper::action_category_move_courses_into($category, $moveto,
283 $courseids);
284 } catch (moodle_exception $ex) {
285 $redirectback = false;
286 $notificationsfail[] = $ex->getMessage();
288 } else if ($bulkmovecategories) {
289 $categoryids = optional_param_array('bcat', array(), PARAM_INT);
290 $movetocatid = required_param('movecategoriesto', PARAM_INT);
291 $movetocat = coursecat::get($movetocatid);
292 $movecount = 0;
293 foreach ($categoryids as $id) {
294 $cattomove = coursecat::get($id);
295 if ($id == $movetocatid) {
296 $notificationsfail[] = get_string('movecategoryownparent', 'error', $cattomove->get_formatted_name());
297 continue;
299 if (strpos($movetocat->path, $cattomove->path) === 0) {
300 $notificationsfail[] = get_string('movecategoryparentconflict', 'error', $cattomove->get_formatted_name());
301 continue;
303 if ($cattomove->parent != $movetocatid) {
304 if ($cattomove->can_change_parent($movetocatid)) {
305 $cattomove->change_parent($movetocatid);
306 $movecount++;
307 } else {
308 $notificationsfail[] = get_string('movecategorynotpossible', 'error', $cattomove->get_formatted_name());
312 if ($movecount > 1) {
313 $a = new stdClass;
314 $a->count = $movecount;
315 $a->to = $movetocat->get_formatted_name();
316 $notificationspass[] = get_string('movecategoriessuccess', 'moodle', $a);
317 } else if ($movecount === 1) {
318 $a = new stdClass;
319 $a->moved = $cattomove->get_formatted_name();
320 $a->to = $movetocat->get_formatted_name();
321 $notificationspass[] = get_string('movecategorysuccess', 'moodle', $a);
323 } else if ($bulkresortcategories) {
324 // Bulk resort selected categories.
325 $categoryids = optional_param_array('bcat', false, PARAM_INT);
326 $sort = required_param('resortcategoriesby', PARAM_ALPHA);
327 if ($categoryids === false) {
328 break;
330 $categories = coursecat::get_many($categoryids);
331 foreach ($categories as $cat) {
332 // Don't clean up here, we'll do it once we're all done.
333 \core_course\management\helper::action_category_resort_subcategories($cat, $sort, false);
335 coursecat::resort_categories_cleanup();
336 if ($category === null && count($categoryids) === 1) {
337 // They're bulk sorting just a single category and they've not selected a category.
338 // Lets for convenience sake auto-select the category that has been resorted for them.
339 redirect(new moodle_url($PAGE->url, array('categoryid' => reset($categoryids))));
343 if ($redirectback) {
344 redirect($PAGE->url);
348 if (!is_null($perpage)) {
349 set_user_preference('coursecat_management_perpage', $perpage);
350 } else {
351 $perpage = get_user_preferences('coursecat_management_perpage', $CFG->coursesperpage);
353 if ((int)$perpage != $perpage || $perpage < 2) {
354 $perpage = $CFG->coursesperpage;
357 $categorysize = 4;
358 $coursesize = 4;
359 $detailssize = 4;
360 if ($viewmode === 'default' || $viewmode === 'combined') {
361 if (isset($courseid)) {
362 $class = 'columns-3';
363 } else {
364 $categorysize = 5;
365 $coursesize = 7;
366 $class = 'columns-2';
368 } else if ($viewmode === 'categories') {
369 $categorysize = 12;
370 $class = 'columns-1';
371 } else if ($viewmode === 'courses') {
372 if (isset($courseid)) {
373 $coursesize = 6;
374 $detailssize = 6;
375 $class = 'columns-2';
376 } else {
377 $coursesize = 12;
378 $class = 'columns-1';
381 if ($viewmode === 'default' || $viewmode === 'combined') {
382 $class .= ' viewmode-cobmined';
383 } else {
384 $class .= ' viewmode-'.$viewmode;
386 if (($viewmode === 'default' || $viewmode === 'combined' || $viewmode === 'courses') && !empty($courseid)) {
387 $class .= ' course-selected';
390 /* @var core_course_management_renderer|core_renderer $renderer */
391 $renderer = $PAGE->get_renderer('core_course', 'management');
392 $renderer->enhance_management_interface();
394 echo $renderer->header();
396 if (!$issearching) {
397 echo $renderer->management_heading(new lang_string('coursecatmanagement'), $viewmode, $categoryid);
398 } else {
399 echo $renderer->management_heading(new lang_string('searchresults'));
402 if (count($notificationspass) > 0) {
403 echo $renderer->notification(join('<br />', $notificationspass), 'notifysuccess');
405 if (count($notificationsfail) > 0) {
406 echo $renderer->notification(join('<br />', $notificationsfail));
409 // Start the management form.
410 echo $renderer->management_form_start();
412 echo $renderer->grid_start('course-category-listings', $class);
413 if ($viewmode === 'default' || $viewmode === 'combined' || $viewmode === 'categories') {
414 echo $renderer->grid_column_start($categorysize, 'category-listing');
415 echo $renderer->category_listing($category);
416 echo $renderer->grid_column_end();
418 if ($viewmode === 'default' || $viewmode === 'combined' || $viewmode === 'courses') {
419 echo $renderer->grid_column_start($coursesize, 'course-listing');
420 if (!$issearching) {
421 echo $renderer->course_listing($category, $course, $page, $perpage);
422 } else {
423 list($courses, $coursescount, $coursestotal) =
424 \core_course\management\helper::search_courses($search, $blocklist, $modulelist, $page, $perpage);
425 echo $renderer->search_listing($courses, $coursestotal, $course, $page, $perpage);
427 echo $renderer->grid_column_end();
428 if (isset($courseid)) {
429 echo $renderer->grid_column_start($detailssize, 'course-detail');
430 echo $renderer->course_detail($course);
431 echo $renderer->grid_column_end();
434 echo $renderer->grid_end();
436 // End of the management form.
437 echo $renderer->management_form_end();
438 echo $renderer->footer();