Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 400 and 402] [Versions 401 and 402]

   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   * Contains the default section course format output class.
  19   *
  20   * @package   core_courseformat
  21   * @copyright 2020 Ferran Recio <ferran@moodle.com>
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace core_courseformat\output\local\content;
  26  
  27  use context_course;
  28  use core\output\named_templatable;
  29  use core_courseformat\base as course_format;
  30  use core_courseformat\output\local\courseformat_named_templatable;
  31  use renderable;
  32  use renderer_base;
  33  use section_info;
  34  use stdClass;
  35  
  36  /**
  37   * Base class to render a course section.
  38   *
  39   * @package   core_courseformat
  40   * @copyright 2020 Ferran Recio <ferran@moodle.com>
  41   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  42   */
  43  class section implements named_templatable, renderable {
  44      use courseformat_named_templatable;
  45  
  46      /** @var course_format the course format */
  47      protected $format;
  48  
  49      /** @var section_info the section info */
  50      protected $section;
  51  
  52      /** @var section header output class */
  53      protected $headerclass;
  54  
  55      /** @var cm list output class */
  56      protected $cmlistclass;
  57  
  58      /** @var section summary output class */
  59      protected $summaryclass;
  60  
  61      /** @var activities summary output class */
  62      protected $cmsummaryclass;
  63  
  64      /** @var section control menu output class */
  65      protected $controlclass;
  66  
  67      /** @var section availability output class */
  68      protected $availabilityclass;
  69  
  70      /** @var optional move here output class */
  71      protected $movehereclass;
  72  
  73      /** @var bool if the title is hidden for some reason */
  74      protected $hidetitle = false;
  75  
  76      /** @var bool if the title is hidden for some reason */
  77      protected $hidecontrols = false;
  78  
  79      /** @var bool if the section is considered stealth */
  80      protected $isstealth = false;
  81  
  82      /** @var string control menu class. */
  83      protected $controlmenuclass;
  84  
  85      /**
  86       * Constructor.
  87       *
  88       * @param course_format $format the course format
  89       * @param section_info $section the section info
  90       */
  91      public function __construct(course_format $format, section_info $section) {
  92          $this->format = $format;
  93          $this->section = $section;
  94  
  95          if ($section->section > $format->get_last_section_number()) {
  96              $this->isstealth = true;
  97          }
  98  
  99          // Load output classes names from format.
 100          $this->headerclass = $format->get_output_classname('content\\section\\header');
 101          $this->cmlistclass = $format->get_output_classname('content\\section\\cmlist');
 102          $this->summaryclass = $format->get_output_classname('content\\section\\summary');
 103          $this->cmsummaryclass = $format->get_output_classname('content\\section\\cmsummary');
 104          $this->controlmenuclass = $format->get_output_classname('content\\section\\controlmenu');
 105          $this->availabilityclass = $format->get_output_classname('content\\section\\availability');
 106          $this->movehereclass = $format->get_output_classname('content\\section\\movehere');
 107      }
 108  
 109      /**
 110       * Hide the section title.
 111       *
 112       * This is used on blocks or in the home page where an isolated section is displayed.
 113       */
 114      public function hide_title(): void {
 115          $this->hidetitle = true;
 116      }
 117  
 118      /**
 119       * Hide the section controls.
 120       *
 121       * This is used on blocks or in the home page where an isolated section is displayed.
 122       */
 123      public function hide_controls(): void {
 124          $this->hidecontrols = true;
 125      }
 126  
 127      /**
 128       * Export this data so it can be used as the context for a mustache template.
 129       *
 130       * @param renderer_base $output typically, the renderer that's calling this function
 131       * @return stdClass data context for a mustache template
 132       */
 133      public function export_for_template(renderer_base $output): stdClass {
 134          global $USER, $PAGE;
 135  
 136          $format = $this->format;
 137          $course = $format->get_course();
 138          $section = $this->section;
 139  
 140          $summary = new $this->summaryclass($format, $section);
 141  
 142          $data = (object)[
 143              'num' => $section->section ?? '0',
 144              'id' => $section->id,
 145              'sectionreturnid' => $format->get_section_number(),
 146              'insertafter' => false,
 147              'summary' => $summary->export_for_template($output),
 148              'highlightedlabel' => $format->get_section_highlighted_name(),
 149              'sitehome' => $course->id == SITEID,
 150              'editing' => $PAGE->user_is_editing()
 151          ];
 152  
 153          $haspartials = [];
 154          $haspartials['availability'] = $this->add_availability_data($data, $output);
 155          $haspartials['visibility'] = $this->add_visibility_data($data, $output);
 156          $haspartials['editor'] = $this->add_editor_data($data, $output);
 157          $haspartials['header'] = $this->add_header_data($data, $output);
 158          $haspartials['cm'] = $this->add_cm_data($data, $output);
 159          $this->add_format_data($data, $haspartials, $output);
 160  
 161          return $data;
 162      }
 163  
 164      /**
 165       * Add the section header to the data structure.
 166       *
 167       * @param stdClass $data the current cm data reference
 168       * @param renderer_base $output typically, the renderer that's calling this function
 169       * @return bool if the cm has name data
 170       */
 171      protected function add_header_data(stdClass &$data, renderer_base $output): bool {
 172          if (!empty($this->hidetitle)) {
 173              return false;
 174          }
 175  
 176          $section = $this->section;
 177          $format = $this->format;
 178  
 179          $header = new $this->headerclass($format, $section);
 180          $headerdata = $header->export_for_template($output);
 181  
 182          // When a section is displayed alone the title goes over the section, not inside it.
 183          if ($section->section != 0 && $section->section == $format->get_section_number()) {
 184              $data->singleheader = $headerdata;
 185          } else {
 186              $data->header = $headerdata;
 187          }
 188          return true;
 189      }
 190  
 191      /**
 192       * Add the section cm list to the data structure.
 193       *
 194       * @param stdClass $data the current cm data reference
 195       * @param renderer_base $output typically, the renderer that's calling this function
 196       * @return bool if the cm has name data
 197       */
 198      protected function add_cm_data(stdClass &$data, renderer_base $output): bool {
 199          $result = false;
 200  
 201          $section = $this->section;
 202          $format = $this->format;
 203  
 204          $showsummary = ($section->section != 0 &&
 205              $section->section != $format->get_section_number() &&
 206              $format->get_course_display() == COURSE_DISPLAY_MULTIPAGE &&
 207              !$format->show_editor()
 208          );
 209  
 210          $showcmlist = $section->uservisible;
 211  
 212          // Add activities summary if necessary.
 213          if ($showsummary) {
 214              $cmsummary = new $this->cmsummaryclass($format, $section);
 215              $data->cmsummary = $cmsummary->export_for_template($output);
 216              $data->onlysummary = true;
 217              $result = true;
 218  
 219              if (!$format->is_section_current($section)) {
 220                  // In multipage, only the current section (and the section zero) has elements.
 221                  $showcmlist = false;
 222              }
 223          }
 224          // Add the cm list.
 225          if ($showcmlist) {
 226              $cmlist = new $this->cmlistclass($format, $section);
 227              $data->cmlist = $cmlist->export_for_template($output);
 228              $result = true;
 229          }
 230          return $result;
 231      }
 232  
 233      /**
 234       * Add the section availability to the data structure.
 235       *
 236       * @param stdClass $data the current cm data reference
 237       * @param renderer_base $output typically, the renderer that's calling this function
 238       * @return bool if the cm has name data
 239       */
 240      protected function add_availability_data(stdClass &$data, renderer_base $output): bool {
 241          $availability = new $this->availabilityclass($this->format, $this->section);
 242          $data->availability = $availability->export_for_template($output);
 243          $data->restrictionlock = !empty($this->section->availableinfo);
 244          $data->hasavailability = $availability->has_availability($output);
 245          return true;
 246      }
 247  
 248      /**
 249       * Add the section vibility information to the data structure.
 250       *
 251       * @param stdClass $data the current cm data reference
 252       * @param renderer_base $output typically, the renderer that's calling this function
 253       * @return bool if the cm has name data
 254       */
 255      protected function add_visibility_data(stdClass &$data, renderer_base $output): bool {
 256          global $USER;
 257          $result = false;
 258          $course = $this->format->get_course();
 259          $context = context_course::instance($course->id);
 260          // Check if it is a stealth sections (orphaned).
 261          if ($this->isstealth) {
 262              $data->isstealth = true;
 263              $data->ishidden = true;
 264              $result = true;
 265          }
 266          if (!$this->section->visible) {
 267              $data->ishidden = true;
 268              $data->notavailable = true;
 269              if (has_capability('moodle/course:viewhiddensections', $context, $USER)) {
 270                  $data->hiddenfromstudents = true;
 271                  $data->notavailable = false;
 272                  $result = true;
 273              }
 274          }
 275          return $result;
 276      }
 277  
 278      /**
 279       * Add the section editor attributes to the data structure.
 280       *
 281       * @param stdClass $data the current cm data reference
 282       * @param renderer_base $output typically, the renderer that's calling this function
 283       * @return bool if the cm has name data
 284       */
 285      protected function add_editor_data(stdClass &$data, renderer_base $output): bool {
 286          $course = $this->format->get_course();
 287          $coursecontext = context_course::instance($course->id);
 288          $editcaps = [];
 289          if (has_capability('moodle/course:sectionvisibility', $coursecontext)) {
 290              $editcaps = ['moodle/course:sectionvisibility'];
 291          }
 292          if (!$this->format->show_editor($editcaps)) {
 293              return false;
 294          }
 295  
 296          if (empty($this->hidecontrols)) {
 297              $controlmenu = new $this->controlmenuclass($this->format, $this->section);
 298              $data->controlmenu = $controlmenu->export_for_template($output);
 299          }
 300          if (!$this->isstealth) {
 301              $data->cmcontrols = $output->course_section_add_cm_control(
 302                  $course,
 303                  $this->section->section,
 304                  $this->format->get_section_number()
 305              );
 306          }
 307          return true;
 308      }
 309  
 310      /**
 311       * Add the section format attributes to the data structure.
 312       *
 313       * @param stdClass $data the current cm data reference
 314       * @param bool[] $haspartials the result of loading partial data elements
 315       * @param renderer_base $output typically, the renderer that's calling this function
 316       * @return bool if the cm has name data
 317       */
 318      protected function add_format_data(stdClass &$data, array $haspartials, renderer_base $output): bool {
 319          $section = $this->section;
 320          $format = $this->format;
 321  
 322          $data->iscoursedisplaymultipage = ($format->get_course_display() == COURSE_DISPLAY_MULTIPAGE);
 323  
 324          if ($data->num === 0 && !$data->iscoursedisplaymultipage) {
 325              $data->collapsemenu = true;
 326          }
 327  
 328          $data->contentcollapsed = $this->is_section_collapsed();
 329  
 330          if ($format->is_section_current($section)) {
 331              $data->iscurrent = true;
 332              $data->currentlink = get_accesshide(
 333                  get_string('currentsection', 'format_' . $format->get_format())
 334              );
 335          }
 336          return true;
 337      }
 338  
 339      /**
 340       * Returns true if the current section should be shown collapsed.
 341       *
 342       * @return bool
 343       */
 344      protected function is_section_collapsed(): bool {
 345          global $PAGE;
 346  
 347          $contentcollapsed = false;
 348          $preferences = $this->format->get_sections_preferences();
 349          if (isset($preferences[$this->section->id])) {
 350              $sectionpreferences = $preferences[$this->section->id];
 351              if (!empty($sectionpreferences->contentcollapsed)) {
 352                  $contentcollapsed = true;
 353              }
 354          }
 355  
 356          // No matter if the user's preference was to collapse the section or not: If the
 357          // 'expandsection' parameter has been specified, it will be shown uncollapsed.
 358          $expandsection = $PAGE->url->get_param('expandsection');
 359          if ($expandsection !== null && $this->section->section == $expandsection) {
 360              $contentcollapsed = false;
 361          }
 362          return $contentcollapsed;
 363      }
 364  }