[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/course/format/singleactivity/ -> lib.php (source)

   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          if ($activity && $activity->sectionnum != 0) {
 234              moveto_module($activity, $modinfo->get_section_info(0));
 235              // Cache was reset so get modinfo again.
 236              $modinfo = get_fast_modinfo($this->courseid);
 237          }
 238  
 239          // Move all other activities into section 1 (the order must be kept).
 240          $hasvisibleactivities = false;
 241          $firstorphanedcm = null;
 242          foreach ($modinfo->sections as $sectionnum => $cmlist) {
 243              if ($sectionnum && !empty($cmlist) && $firstorphanedcm === null) {
 244                  $firstorphanedcm = reset($cmlist);
 245              }
 246              foreach ($cmlist as $cmid) {
 247                  if ($sectionnum > 1) {
 248                      moveto_module($modinfo->get_cm($cmid), $modinfo->get_section_info(1));
 249                  } else if (!$hasvisibleactivities && $sectionnum == 1 && $modinfo->get_cm($cmid)->visible) {
 250                      $hasvisibleactivities = true;
 251                  }
 252              }
 253          }
 254          if (!empty($modinfo->sections[0])) {
 255              foreach ($modinfo->sections[0] as $cmid) {
 256                  if (!$activity || $cmid != $activity->id) {
 257                      moveto_module($modinfo->get_cm($cmid), $modinfo->get_section_info(1), $firstorphanedcm);
 258                  }
 259              }
 260          }
 261          if ($hasvisibleactivities) {
 262              set_section_visible($this->courseid, 1, false);
 263          }
 264          return $activity;
 265      }
 266  
 267      /**
 268       * Returns the name of activity type used for this course
 269       *
 270       * @return string|null
 271       */
 272      protected function get_activitytype() {
 273          $options = $this->get_format_options();
 274          $availabletypes = $this->get_supported_activities();
 275          if (!empty($options['activitytype']) &&
 276                  array_key_exists($options['activitytype'], $availabletypes)) {
 277              return $options['activitytype'];
 278          } else {
 279              return null;
 280          }
 281      }
 282  
 283      /**
 284       * Returns the current activity if exists
 285       *
 286       * @return null|cm_info
 287       */
 288      protected function get_activity() {
 289          if ($this->activity === false) {
 290              $this->activity = $this->reorder_activities();
 291          }
 292          return $this->activity;
 293      }
 294  
 295      /**
 296       * Get the activities supported by the format.
 297       *
 298       * Here we ignore the modules that do not have a page of their own, like the label.
 299       *
 300       * @return array array($module => $name of the module).
 301       */
 302      public static function get_supported_activities() {
 303          $availabletypes = get_module_types_names();
 304          foreach ($availabletypes as $module => $name) {
 305              if (plugin_supports('mod', $module, FEATURE_NO_VIEW_LINK, false)) {
 306                  unset($availabletypes[$module]);
 307              }
 308          }
 309          return $availabletypes;
 310      }
 311  
 312      /**
 313       * Checks if the current user can add the activity of the specified type to this course.
 314       *
 315       * @return bool
 316       */
 317      protected function can_add_activity() {
 318          global $CFG;
 319          if (!($modname = $this->get_activitytype())) {
 320              return false;
 321          }
 322          if (!has_capability('moodle/course:manageactivities', context_course::instance($this->courseid))) {
 323              return false;
 324          }
 325          if (!course_allowed_module($this->get_course(), $modname)) {
 326              return false;
 327          }
 328          $libfile = "$CFG->dirroot/mod/$modname/lib.php";
 329          if (!file_exists($libfile)) {
 330              return null;
 331          }
 332          return true;
 333      }
 334  
 335      /**
 336       * Checks if the activity type requires subtypes.
 337       *
 338       * @return bool|null (null if the check is not possible)
 339       */
 340      public function activity_has_subtypes() {
 341          global $CFG;
 342          if (!($modname = $this->get_activitytype())) {
 343              return null;
 344          }
 345          $libfile = "$CFG->dirroot/mod/$modname/lib.php";
 346          if (!file_exists($libfile)) {
 347              return null;
 348          }
 349          include_once($libfile);
 350          return function_exists($modname. '_get_types');
 351      }
 352  
 353      /**
 354       * Allows course format to execute code on moodle_page::set_course()
 355       *
 356       * This function is executed before the output starts.
 357       *
 358       * If everything is configured correctly, user is redirected from the
 359       * default course view page to the activity view page.
 360       *
 361       * "Section 1" is the administrative page to manage orphaned activities
 362       *
 363       * If user is on course view page and there is no module added to the course
 364       * and the user has 'moodle/course:manageactivities' capability, redirect to create module
 365       * form.
 366       *
 367       * @param moodle_page $page instance of page calling set_course
 368       */
 369      public function page_set_course(moodle_page $page) {
 370          global $PAGE;
 371          $page->add_body_class('format-'. $this->get_format());
 372          if ($PAGE == $page && $page->has_set_url() &&
 373                  $page->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)) {
 374              $edit = optional_param('edit', -1, PARAM_BOOL);
 375              if (($edit == 0 || $edit == 1) && confirm_sesskey()) {
 376                  // This is a request to turn editing mode on or off, do not redirect here, /course/view.php will do redirection.
 377                  return;
 378              }
 379              $cm = $this->get_activity();
 380              $cursection = optional_param('section', null, PARAM_INT);
 381              if (!empty($cursection) && has_capability('moodle/course:viewhiddensections',
 382                      context_course::instance($this->courseid))) {
 383                  // Display orphaned activities (course view page, section 1).
 384                  return;
 385              }
 386              if (!$this->get_activitytype()) {
 387                  if (has_capability('moodle/course:update', context_course::instance($this->courseid))) {
 388                      // Teacher is redirected to edit course page.
 389                      $url = new moodle_url('/course/edit.php', array('id' => $this->courseid));
 390                      redirect($url, get_string('erroractivitytype', 'format_singleactivity'));
 391                  } else {
 392                      // Student sees an empty course page.
 393                      return;
 394                  }
 395              }
 396              if ($cm === null) {
 397                  if ($this->can_add_activity()) {
 398                      // This is a user who has capability to create an activity.
 399                      if ($this->activity_has_subtypes()) {
 400                          // Activity that requires subtype can not be added automatically.
 401                          if (optional_param('addactivity', 0, PARAM_INT)) {
 402                              return;
 403                          } else {
 404                              $url = new moodle_url('/course/view.php', array('id' => $this->courseid, 'addactivity' => 1));
 405                              redirect($url);
 406                          }
 407                      }
 408                      // Redirect to the add activity form.
 409                      $url = new moodle_url('/course/mod.php', array('id' => $this->courseid,
 410                          'section' => 0, 'sesskey' => sesskey(), 'add' => $this->get_activitytype()));
 411                      redirect($url);
 412                  } else {
 413                      // Student views an empty course page.
 414                      return;
 415                  }
 416              } else if (!$cm->uservisible || !$cm->url) {
 417                  // Activity is set but not visible to current user or does not have url.
 418                  // Display course page (either empty or with availability restriction info).
 419                  return;
 420              } else {
 421                  // Everything is set up and accessible, redirect to the activity page!
 422                  redirect($cm->url);
 423              }
 424          }
 425      }
 426  
 427      /**
 428       * Allows course format to execute code on moodle_page::set_cm()
 429       *
 430       * If we are inside the main module for this course, remove extra node level
 431       * from navigation: substitute course node with activity node, move all children
 432       *
 433       * @param moodle_page $page instance of page calling set_cm
 434       */
 435      public function page_set_cm(moodle_page $page) {
 436          global $PAGE;
 437          parent::page_set_cm($page);
 438          if ($PAGE == $page && ($cm = $this->get_activity()) &&
 439                  $cm->uservisible &&
 440                  ($cm->id === $page->cm->id) &&
 441                  ($activitynode = $page->navigation->find($cm->id, navigation_node::TYPE_ACTIVITY)) &&
 442                  ($node = $page->navigation->find($page->course->id, navigation_node::TYPE_COURSE))) {
 443              // Substitute course node with activity node, move all children.
 444              $node->action = $activitynode->action;
 445              $node->type = $activitynode->type;
 446              $node->id = $activitynode->id;
 447              $node->key = $activitynode->key;
 448              $node->isactive = $node->isactive || $activitynode->isactive;
 449              $node->icon = null;
 450              if ($activitynode->children->count()) {
 451                  foreach ($activitynode->children as &$child) {
 452                      $child->remove();
 453                      $node->add_node($child);
 454                  }
 455              } else {
 456                  $node->search_for_active_node();
 457              }
 458              $activitynode->remove();
 459          }
 460      }
 461  
 462      /**
 463       * Returns true if the course has a front page.
 464       *
 465       * @return boolean false
 466       */
 467      public function has_view_page() {
 468          return false;
 469      }
 470  
 471  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1