[ Index ]

PHP Cross Reference of Unnamed Project

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          $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  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1