[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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. 13 // 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/>. 16 17 /** 18 * This file contains main class for the course format singleactivity 19 * 20 * @package format_singleactivity 21 * @copyright 2012 Marina Glancy 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 require_once($CFG->dirroot. '/course/format/lib.php'); 27 28 /** 29 * Main class for the singleactivity course format 30 * 31 * @package format_singleactivity 32 * @copyright 2012 Marina Glancy 33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 */ 35 class format_singleactivity extends format_base { 36 /** @var cm_info the current activity. Use get_activity() to retrieve it. */ 37 private $activity = false; 38 39 /** 40 * The URL to use for the specified course 41 * 42 * @param int|stdClass $section Section object from database or just field course_sections.section 43 * if null the course view page is returned 44 * @param array $options options for view URL. At the moment core uses: 45 * 'navigation' (bool) if true and section has no separate page, the function returns null 46 * 'sr' (int) used by multipage formats to specify to which section to return 47 * @return null|moodle_url 48 */ 49 public function get_view_url($section, $options = array()) { 50 $sectionnum = $section; 51 if (is_object($sectionnum)) { 52 $sectionnum = $section->section; 53 } 54 if ($sectionnum == 1) { 55 return new moodle_url('/course/view.php', array('id' => $this->courseid, 'section' => 1)); 56 } 57 if (!empty($options['navigation']) && $section !== null) { 58 return null; 59 } 60 return new moodle_url('/course/view.php', array('id' => $this->courseid)); 61 } 62 63 /** 64 * Loads all of the course sections into the navigation 65 * 66 * @param global_navigation $navigation 67 * @param navigation_node $node The course node within the navigation 68 */ 69 public function extend_course_navigation($navigation, navigation_node $node) { 70 // Display orphaned activities for the users who can see them. 71 $context = context_course::instance($this->courseid); 72 if (has_capability('moodle/course:viewhiddensections', $context)) { 73 $modinfo = get_fast_modinfo($this->courseid); 74 if (!empty($modinfo->sections[1])) { 75 $section1 = $modinfo->get_section_info(1); 76 // Show orphaned activities. 77 $orphanednode = $node->add(get_string('orphaned', 'format_singleactivity'), 78 $this->get_view_url(1), navigation_node::TYPE_SECTION, null, $section1->id); 79 $orphanednode->nodetype = navigation_node::NODETYPE_BRANCH; 80 $orphanednode->add_class('orphaned'); 81 foreach ($modinfo->sections[1] as $cmid) { 82 if (has_capability('moodle/course:viewhiddenactivities', context_module::instance($cmid))) { 83 $this->navigation_add_activity($orphanednode, $modinfo->cms[$cmid]); 84 } 85 } 86 } 87 } 88 } 89 90 /** 91 * Adds a course module to the navigation node 92 * 93 * This is basically copied from function global_navigation::load_section_activities() 94 * because it is not accessible from outside. 95 * 96 * @param navigation_node $node 97 * @param cm_info $cm 98 * @return null|navigation_node 99 */ 100 protected function navigation_add_activity(navigation_node $node, $cm) { 101 if (!$cm->uservisible) { 102 return null; 103 } 104 $action = $cm->url; 105 if (!$action) { 106 // Do not add to navigation activity without url (i.e. labels). 107 return null; 108 } 109 $activityname = format_string($cm->name, true, array('context' => context_module::instance($cm->id))); 110 if ($cm->icon) { 111 $icon = new pix_icon($cm->icon, $cm->modfullname, $cm->iconcomponent); 112 } else { 113 $icon = new pix_icon('icon', $cm->modfullname, $cm->modname); 114 } 115 $activitynode = $node->add($activityname, $action, navigation_node::TYPE_ACTIVITY, null, $cm->id, $icon); 116 if (global_navigation::module_extends_navigation($cm->modname)) { 117 $activitynode->nodetype = navigation_node::NODETYPE_BRANCH; 118 } else { 119 $activitynode->nodetype = navigation_node::NODETYPE_LEAF; 120 } 121 return $activitynode; 122 } 123 124 /** 125 * Returns the list of blocks to be automatically added for the newly created course 126 * 127 * @return array of default blocks, must contain two keys BLOCK_POS_LEFT and BLOCK_POS_RIGHT 128 * each of values is an array of block names (for left and right side columns) 129 */ 130 public function get_default_blocks() { 131 // No blocks for this format because course view page is not displayed anyway. 132 return array( 133 BLOCK_POS_LEFT => array(), 134 BLOCK_POS_RIGHT => array() 135 ); 136 } 137 138 /** 139 * Definitions of the additional options that this course format uses for course 140 * 141 * Singleactivity course format uses one option 'activitytype' 142 * 143 * @param bool $foreditform 144 * @return array of options 145 */ 146 public function course_format_options($foreditform = false) { 147 static $courseformatoptions = false; 148 if ($courseformatoptions === false) { 149 $config = get_config('format_singleactivity'); 150 $courseformatoptions = array( 151 'activitytype' => array( 152 'default' => $config->activitytype, 153 'type' => PARAM_TEXT, 154 ), 155 ); 156 } 157 if ($foreditform && !isset($courseformatoptions['activitytype']['label'])) { 158 $availabletypes = $this->get_supported_activities(); 159 $courseformatoptionsedit = array( 160 'activitytype' => array( 161 'label' => new lang_string('activitytype', 'format_singleactivity'), 162 'help' => 'activitytype', 163 'help_component' => 'format_singleactivity', 164 'element_type' => 'select', 165 'element_attributes' => array($availabletypes), 166 ), 167 ); 168 $courseformatoptions = array_merge_recursive($courseformatoptions, $courseformatoptionsedit); 169 } 170 return $courseformatoptions; 171 } 172 173 /** 174 * Adds format options elements to the course/section edit form 175 * 176 * This function is called from {@link course_edit_form::definition_after_data()} 177 * 178 * Format singleactivity adds a warning when format of the course is about to be changed. 179 * 180 * @param MoodleQuickForm $mform form the elements are added to 181 * @param bool $forsection 'true' if this is a section edit form, 'false' if this is course edit form 182 * @return array array of references to the added form elements 183 */ 184 public function create_edit_form_elements(&$mform, $forsection = false) { 185 global $PAGE; 186 $elements = parent::create_edit_form_elements($mform, $forsection); 187 if (!$forsection && ($course = $PAGE->course) && !empty($course->format) && 188 $course->format !== 'site' && $course->format !== 'singleactivity') { 189 // This is the existing course in other format, display a warning. 190 $element = $mform->addElement('static', '', '', 191 html_writer::tag('span', get_string('warningchangeformat', 'format_singleactivity'), 192 array('class' => 'error'))); 193 array_unshift($elements, $element); 194 } 195 return $elements; 196 } 197 198 /** 199 * Make sure that current active activity is in section 0 200 * 201 * All other activities are moved to section 1 that will be displayed as 'Orphaned'. 202 * It may be needed after the course format was changed or activitytype in 203 * course settings has been changed. 204 * 205 * @return null|cm_info current activity 206 */ 207 public function reorder_activities() { 208 course_create_sections_if_missing($this->courseid, array(0, 1)); 209 foreach ($this->get_sections() as $sectionnum => $section) { 210 if (($sectionnum && $section->visible) || 211 (!$sectionnum && !$section->visible)) { 212 // Make sure that 0 section is visible and all others are hidden. 213 set_section_visible($this->courseid, $sectionnum, $sectionnum == 0); 214 } 215 } 216 $modinfo = get_fast_modinfo($this->courseid); 217 218 // Find the current activity (first activity with the specified type in all course activities). 219 $activitytype = $this->get_activitytype(); 220 $activity = null; 221 if (!empty($activitytype)) { 222 foreach ($modinfo->sections as $sectionnum => $cmlist) { 223 foreach ($cmlist as $cmid) { 224 if ($modinfo->cms[$cmid]->modname === $activitytype) { 225 $activity = $modinfo->cms[$cmid]; 226 break 2; 227 } 228 } 229 } 230 } 231 232 // Make sure the current activity is in the 0-section. 233 $changed = false; 234 if ($activity && $activity->sectionnum != 0) { 235 moveto_module($activity, $modinfo->get_section_info(0)); 236 $changed = true; 237 } 238 if ($activity && !$activity->visible) { 239 set_coursemodule_visible($activity->id, 1); 240 $changed = true; 241 } 242 if ($changed) { 243 // Cache was reset so get modinfo again. 244 $modinfo = get_fast_modinfo($this->courseid); 245 } 246 247 // Move all other activities into section 1 (the order must be kept). 248 $hasvisibleactivities = false; 249 $firstorphanedcm = null; 250 foreach ($modinfo->sections as $sectionnum => $cmlist) { 251 if ($sectionnum && !empty($cmlist) && $firstorphanedcm === null) { 252 $firstorphanedcm = reset($cmlist); 253 } 254 foreach ($cmlist as $cmid) { 255 if ($sectionnum > 1) { 256 moveto_module($modinfo->get_cm($cmid), $modinfo->get_section_info(1)); 257 } else if (!$hasvisibleactivities && $sectionnum == 1 && $modinfo->get_cm($cmid)->visible) { 258 $hasvisibleactivities = true; 259 } 260 } 261 } 262 if (!empty($modinfo->sections[0])) { 263 foreach ($modinfo->sections[0] as $cmid) { 264 if (!$activity || $cmid != $activity->id) { 265 moveto_module($modinfo->get_cm($cmid), $modinfo->get_section_info(1), $firstorphanedcm); 266 } 267 } 268 } 269 if ($hasvisibleactivities) { 270 set_section_visible($this->courseid, 1, false); 271 } 272 return $activity; 273 } 274 275 /** 276 * Returns the name of activity type used for this course 277 * 278 * @return string|null 279 */ 280 protected function get_activitytype() { 281 $options = $this->get_format_options(); 282 $availabletypes = $this->get_supported_activities(); 283 if (!empty($options['activitytype']) && 284 array_key_exists($options['activitytype'], $availabletypes)) { 285 return $options['activitytype']; 286 } else { 287 return null; 288 } 289 } 290 291 /** 292 * Returns the current activity if exists 293 * 294 * @return null|cm_info 295 */ 296 protected function get_activity() { 297 if ($this->activity === false) { 298 $this->activity = $this->reorder_activities(); 299 } 300 return $this->activity; 301 } 302 303 /** 304 * Get the activities supported by the format. 305 * 306 * Here we ignore the modules that do not have a page of their own, like the label. 307 * 308 * @return array array($module => $name of the module). 309 */ 310 public static function get_supported_activities() { 311 $availabletypes = get_module_types_names(); 312 foreach ($availabletypes as $module => $name) { 313 if (plugin_supports('mod', $module, FEATURE_NO_VIEW_LINK, false)) { 314 unset($availabletypes[$module]); 315 } 316 } 317 return $availabletypes; 318 } 319 320 /** 321 * Checks if the current user can add the activity of the specified type to this course. 322 * 323 * @return bool 324 */ 325 protected function can_add_activity() { 326 global $CFG; 327 if (!($modname = $this->get_activitytype())) { 328 return false; 329 } 330 if (!has_capability('moodle/course:manageactivities', context_course::instance($this->courseid))) { 331 return false; 332 } 333 if (!course_allowed_module($this->get_course(), $modname)) { 334 return false; 335 } 336 $libfile = "$CFG->dirroot/mod/$modname/lib.php"; 337 if (!file_exists($libfile)) { 338 return null; 339 } 340 return true; 341 } 342 343 /** 344 * Checks if the activity type has multiple items in the activity chooser. 345 * This may happen as a result of defining callback modulename_get_shortcuts() 346 * or [deprecated] modulename_get_types() - TODO MDL-53697 remove this line. 347 * 348 * @return bool|null (null if the check is not possible) 349 */ 350 public function activity_has_subtypes() { 351 if (!($modname = $this->get_activitytype())) { 352 return null; 353 } 354 $metadata = get_module_metadata($this->get_course(), self::get_supported_activities()); 355 foreach ($metadata as $key => $moduledata) { 356 if (preg_match('/^'.$modname.':/', $key)) { 357 return true; 358 } 359 } 360 return false; 361 } 362 363 /** 364 * Allows course format to execute code on moodle_page::set_course() 365 * 366 * This function is executed before the output starts. 367 * 368 * If everything is configured correctly, user is redirected from the 369 * default course view page to the activity view page. 370 * 371 * "Section 1" is the administrative page to manage orphaned activities 372 * 373 * If user is on course view page and there is no module added to the course 374 * and the user has 'moodle/course:manageactivities' capability, redirect to create module 375 * form. 376 * 377 * @param moodle_page $page instance of page calling set_course 378 */ 379 public function page_set_course(moodle_page $page) { 380 global $PAGE; 381 $page->add_body_class('format-'. $this->get_format()); 382 if ($PAGE == $page && $page->has_set_url() && 383 $page->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)) { 384 $edit = optional_param('edit', -1, PARAM_BOOL); 385 if (($edit == 0 || $edit == 1) && confirm_sesskey()) { 386 // This is a request to turn editing mode on or off, do not redirect here, /course/view.php will do redirection. 387 return; 388 } 389 $cm = $this->get_activity(); 390 $cursection = optional_param('section', null, PARAM_INT); 391 if (!empty($cursection) && has_capability('moodle/course:viewhiddensections', 392 context_course::instance($this->courseid))) { 393 // Display orphaned activities (course view page, section 1). 394 return; 395 } 396 if (!$this->get_activitytype()) { 397 if (has_capability('moodle/course:update', context_course::instance($this->courseid))) { 398 // Teacher is redirected to edit course page. 399 $url = new moodle_url('/course/edit.php', array('id' => $this->courseid)); 400 redirect($url, get_string('erroractivitytype', 'format_singleactivity')); 401 } else { 402 // Student sees an empty course page. 403 return; 404 } 405 } 406 if ($cm === null) { 407 if ($this->can_add_activity()) { 408 // This is a user who has capability to create an activity. 409 if ($this->activity_has_subtypes()) { 410 // Activity has multiple items in the activity chooser, it can not be added automatically. 411 if (optional_param('addactivity', 0, PARAM_INT)) { 412 return; 413 } else { 414 $url = new moodle_url('/course/view.php', array('id' => $this->courseid, 'addactivity' => 1)); 415 redirect($url); 416 } 417 } 418 // Redirect to the add activity form. 419 $url = new moodle_url('/course/mod.php', array('id' => $this->courseid, 420 'section' => 0, 'sesskey' => sesskey(), 'add' => $this->get_activitytype())); 421 redirect($url); 422 } else { 423 // Student views an empty course page. 424 return; 425 } 426 } else if (!$cm->uservisible || !$cm->url) { 427 // Activity is set but not visible to current user or does not have url. 428 // Display course page (either empty or with availability restriction info). 429 return; 430 } else { 431 // Everything is set up and accessible, redirect to the activity page! 432 redirect($cm->url); 433 } 434 } 435 } 436 437 /** 438 * Allows course format to execute code on moodle_page::set_cm() 439 * 440 * If we are inside the main module for this course, remove extra node level 441 * from navigation: substitute course node with activity node, move all children 442 * 443 * @param moodle_page $page instance of page calling set_cm 444 */ 445 public function page_set_cm(moodle_page $page) { 446 global $PAGE; 447 parent::page_set_cm($page); 448 if ($PAGE == $page && ($cm = $this->get_activity()) && 449 $cm->uservisible && 450 ($cm->id === $page->cm->id) && 451 ($activitynode = $page->navigation->find($cm->id, navigation_node::TYPE_ACTIVITY)) && 452 ($node = $page->navigation->find($page->course->id, navigation_node::TYPE_COURSE))) { 453 // Substitute course node with activity node, move all children. 454 $node->action = $activitynode->action; 455 $node->type = $activitynode->type; 456 $node->id = $activitynode->id; 457 $node->key = $activitynode->key; 458 $node->isactive = $node->isactive || $activitynode->isactive; 459 $node->icon = null; 460 if ($activitynode->children->count()) { 461 foreach ($activitynode->children as &$child) { 462 $child->remove(); 463 $node->add_node($child); 464 } 465 } else { 466 $node->search_for_active_node(); 467 } 468 $activitynode->remove(); 469 } 470 } 471 472 /** 473 * Returns true if the course has a front page. 474 * 475 * @return boolean false 476 */ 477 public function has_view_page() { 478 return false; 479 } 480 481 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |