Search moodle.org's
Developer Documentation

See Release Notes

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

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

   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 activity list from a section.
  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 cm_info;
  28  use context_course;
  29  use core\output\named_templatable;
  30  use core_availability\info_module;
  31  use core_courseformat\base as course_format;
  32  use core_courseformat\output\local\courseformat_named_templatable;
  33  use renderable;
  34  use renderer_base;
  35  use section_info;
  36  use stdClass;
  37  
  38  /**
  39   * Base class to render a course module inside a course format.
  40   *
  41   * @package   core_courseformat
  42   * @copyright 2020 Ferran Recio <ferran@moodle.com>
  43   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  44   */
  45  class cm implements named_templatable, renderable {
  46      use courseformat_named_templatable;
  47  
  48      /** @var course_format the course format */
  49      protected $format;
  50  
  51      /** @var section_info the section object */
  52      private $section;
  53  
  54      /** @var cm_info the course module instance */
  55      protected $mod;
  56  
  57      /** @var array optional display options */
  58      protected $displayoptions;
  59  
  60      /** @var string the activity name output class name */
  61      protected $cmnameclass;
  62  
  63      /** @var string the activity control menu class name */
  64      protected $controlmenuclass;
  65  
  66      /** @var string the activity availability class name */
  67      protected $availabilityclass;
  68  
  69      /** @var string the activity completion class name */
  70      protected $completionclass;
  71  
  72      /** @var string the activity visibility class name */
  73      protected $visibilityclass;
  74  
  75      /** @var string the activity groupmode badge class name */
  76      protected $groupmodeclass;
  77  
  78      /**
  79       * Constructor.
  80       *
  81       * @param course_format $format the course format
  82       * @param section_info $section the section info
  83       * @param cm_info $mod the course module ionfo
  84       * @param array $displayoptions optional extra display options
  85       */
  86      public function __construct(course_format $format, section_info $section, cm_info $mod, array $displayoptions = []) {
  87          $this->format = $format;
  88          $this->section = $section;
  89          $this->mod = $mod;
  90  
  91          // Add extra display options.
  92          $this->displayoptions = $displayoptions;
  93          $this->load_classes();
  94  
  95          // Get the necessary classes.
  96          $this->cmnameclass = $format->get_output_classname('content\\cm\\cmname');
  97          $this->controlmenuclass = $format->get_output_classname('content\\cm\\controlmenu');
  98          $this->availabilityclass = $format->get_output_classname('content\\cm\\availability');
  99          $this->completionclass = $format->get_output_classname('content\\cm\\completion');
 100          $this->visibilityclass = $format->get_output_classname('content\\cm\\visibility');
 101          $this->groupmodeclass = $format->get_output_classname('content\\cm\\groupmode');
 102      }
 103  
 104      /**
 105       * Export this data so it can be used as the context for a mustache template.
 106       *
 107       * @param renderer_base $output typically, the renderer that's calling this function
 108       * @return stdClass data context for a mustache template
 109       */
 110      public function export_for_template(renderer_base $output): stdClass {
 111          global $PAGE;
 112  
 113          $mod = $this->mod;
 114          $displayoptions = $this->displayoptions;
 115  
 116          $data = (object)[
 117              'grouping' => $mod->get_grouping_label($displayoptions['textclasses']),
 118              'modname' => get_string('pluginname', 'mod_' . $mod->modname),
 119              'url' => $mod->url,
 120              'activityname' => $mod->get_formatted_name(),
 121              'textclasses' => $displayoptions['textclasses'],
 122              'classlist' => [],
 123              'cmid' => $mod->id,
 124              'editing' => $PAGE->user_is_editing(),
 125          ];
 126  
 127          // Add partial data segments.
 128          $haspartials = [];
 129          $haspartials['cmname'] = $this->add_cm_name_data($data, $output);
 130          $haspartials['availability'] = $this->add_availability_data($data, $output);
 131          $haspartials['alternative'] = $this->add_alternative_content_data($data, $output);
 132          $haspartials['completion'] = $this->add_completion_data($data, $output);
 133          $haspartials['dates'] = $this->add_dates_data($data, $output);
 134          $haspartials['editor'] = $this->add_editor_data($data, $output);
 135          $haspartials['groupmode'] = $this->add_groupmode_data($data, $output);
 136          $haspartials['visibility'] = $this->add_visibility_data($data, $output);
 137          $this->add_format_data($data, $haspartials, $output);
 138  
 139          // Calculated fields.
 140          if (!empty($data->url)) {
 141              $data->hasurl = true;
 142          }
 143          return $data;
 144      }
 145  
 146      /**
 147       * Add course module name attributes to the data structure.
 148       *
 149       * @param stdClass $data the current cm data reference
 150       * @param renderer_base $output typically, the renderer that's calling this function
 151       * @return bool if the cm has name data
 152       */
 153      protected function add_cm_name_data(stdClass &$data, renderer_base $output): bool {
 154          // Mod inplace name editable.
 155          $cmname = new $this->cmnameclass(
 156              $this->format,
 157              $this->section,
 158              $this->mod,
 159              null,
 160              $this->displayoptions
 161          );
 162          $data->cmname = $cmname->export_for_template($output);
 163          $data->hasname = $cmname->has_name();
 164          return $data->hasname;
 165      }
 166  
 167      /**
 168       * Add the module availability to the data structure.
 169       *
 170       * @param stdClass $data the current cm data reference
 171       * @param renderer_base $output typically, the renderer that's calling this function
 172       * @return bool if the cm has mod availability
 173       */
 174      protected function add_availability_data(stdClass &$data, renderer_base $output): bool {
 175          if (!$this->mod->visible) {
 176              $data->modavailability = null;
 177              return false;
 178          }
 179          // Mod availability output class.
 180          $availability = new $this->availabilityclass(
 181              $this->format,
 182              $this->section,
 183              $this->mod,
 184              $this->displayoptions
 185          );
 186          $modavailability = $availability->export_for_template($output);
 187          $data->modavailability = $modavailability;
 188          return $availability->has_availability($output);
 189      }
 190  
 191      /**
 192       * Add the alternative content 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 alternative content
 197       */
 198      protected function add_alternative_content_data(stdClass &$data, renderer_base $output): bool {
 199          $altcontent = $this->mod->get_formatted_content(
 200              ['overflowdiv' => true, 'noclean' => true]
 201          );
 202          $data->altcontent = (empty($altcontent)) ? false : $altcontent;
 203          $data->afterlink = $this->mod->afterlink;
 204  
 205          $activitybadgedata = $this->mod->get_activitybadge($output);
 206          if (!empty($activitybadgedata)) {
 207              $data->activitybadge = $activitybadgedata;
 208          }
 209  
 210          return !empty($data->altcontent);
 211      }
 212  
 213      /**
 214       * Add activity dates information to the data structure.
 215       *
 216       * @param stdClass $data the current cm data reference
 217       * @param renderer_base $output typically, the renderer that's calling this function
 218       * @return bool the module has completion information
 219       */
 220      protected function add_dates_data(stdClass &$data, renderer_base $output): bool {
 221          global $USER;
 222          $course = $this->mod->get_course();
 223          if (!$course->showactivitydates) {
 224              return false;
 225          }
 226          $activitydates = \core\activity_dates::get_dates_for_module($this->mod, $USER->id);
 227          $templatedata = new \core_course\output\activity_dates($activitydates);
 228          $data->dates = $templatedata->export_for_template($output);
 229  
 230          return $data->dates->hasdates;
 231      }
 232  
 233      /**
 234       * Add activity completion information 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 the module has completion information
 239       */
 240      protected function add_completion_data(stdClass &$data, renderer_base $output): bool {
 241          $completion = new $this->completionclass($this->format, $this->section, $this->mod);
 242          $templatedata = $completion->export_for_template($output);
 243          if ($templatedata) {
 244              $data->completion = $templatedata;
 245              return true;
 246          }
 247          return false;
 248      }
 249  
 250      /**
 251       * Add activity information to the data structure.
 252       *
 253       * @param stdClass $data the current cm data reference
 254       * @param bool[] $haspartials the result of loading partial data elements
 255       * @param renderer_base $output typically, the renderer that's calling this function
 256       * @return bool if the cm has format data
 257       */
 258      protected function add_format_data(stdClass &$data, array $haspartials, renderer_base $output): bool {
 259          $result = false;
 260          // Legacy indentation.
 261          if (!empty($this->mod->indent) && $this->format->uses_indentation()) {
 262              $data->indent = $this->mod->indent;
 263              if ($this->mod->indent > 15) {
 264                  $data->hugeindent = true;
 265                  $result = true;
 266              }
 267          }
 268          // Stealth and hidden from student.
 269          if (!$this->mod->visible) {
 270              // This module is hidden but current user has capability to see it.
 271              $data->modhiddenfromstudents = true;
 272              $result = true;
 273          } else if ($this->mod->is_stealth()) {
 274              // This module is available but is normally not displayed on the course page
 275              // (this user can see it because they can manage it).
 276              $data->modstealth = true;
 277              $result = true;
 278          }
 279          // Special inline activity format.
 280          if (
 281              $this->mod->has_custom_cmlist_item() &&
 282              !$haspartials['availability'] &&
 283              !$haspartials['completion'] &&
 284              !$haspartials['dates'] &&
 285              !$haspartials['groupmode'] &&
 286              !isset($data->modhiddenfromstudents) &&
 287              !isset($data->modstealth) &&
 288              !$this->format->show_editor()
 289          ) {
 290              $data->modinline = true;
 291              $result = true;
 292          }
 293          return $result;
 294      }
 295  
 296      /**
 297       * Add course editor attributes to the data structure.
 298       *
 299       * @param stdClass $data the current cm data reference
 300       * @param renderer_base $output typically, the renderer that's calling this function
 301       * @return bool if the cm has editor data
 302       */
 303      protected function add_editor_data(stdClass &$data, renderer_base $output): bool {
 304          $course = $this->format->get_course();
 305          $coursecontext = context_course::instance($course->id);
 306          $editcaps = [];
 307          if (has_capability('moodle/course:activityvisibility', $coursecontext)) {
 308              $editcaps = ['moodle/course:activityvisibility'];
 309          }
 310          if (!$this->format->show_editor($editcaps)) {
 311              return false;
 312          }
 313          $returnsection = $this->format->get_section_number();
 314          // Edit actions.
 315          $controlmenu = new $this->controlmenuclass(
 316              $this->format,
 317              $this->section,
 318              $this->mod,
 319              $this->displayoptions
 320          );
 321          $data->controlmenu = $controlmenu->export_for_template($output);
 322          if (!$this->format->supports_components()) {
 323              // Add the legacy YUI move link.
 324              $data->moveicon = course_get_cm_move($this->mod, $returnsection);
 325          }
 326          return true;
 327      }
 328  
 329      /**
 330       * Add group mode information to the data structure.
 331       *
 332       * @param stdClass $data the current cm data reference
 333       * @param renderer_base $output typically, the renderer that's calling this function
 334       * @return bool the module has group mode information
 335       */
 336      protected function add_groupmode_data(stdClass &$data, renderer_base $output): bool {
 337          $groupmode = new $this->groupmodeclass($this->format, $this->section, $this->mod);
 338          $data->groupmodeinfo = $groupmode->export_for_template($output);
 339          return !empty($data->groupmodeinfo);
 340      }
 341  
 342      /**
 343       * Add visibility information to the data structure.
 344       *
 345       * @param stdClass $data the current cm data reference
 346       * @param renderer_base $output typically, the renderer that's calling this function
 347       * @return bool if the cm has visibility data
 348       */
 349      protected function add_visibility_data(stdClass &$data, renderer_base $output): bool {
 350          $visibility = new $this->visibilityclass($this->format, $this->section, $this->mod);
 351          $templatedata = $visibility->export_for_template($output);
 352          if ($templatedata) {
 353              $data->visibility = $templatedata;
 354              return true;
 355          }
 356          return false;
 357      }
 358  
 359      /**
 360       * Returns the CSS classes for the activity name/content
 361       *
 362       */
 363      protected function load_classes() {
 364          $mod = $this->mod;
 365  
 366          $linkclasses = '';
 367          $textclasses = '';
 368          if ($mod->uservisible) {
 369              $info = new info_module($mod);
 370              $conditionalhidden = !$info->is_available_for_all();
 371              $accessiblebutdim = (!$mod->visible || $conditionalhidden) &&
 372                  has_capability('moodle/course:viewhiddenactivities', $mod->context);
 373              if ($accessiblebutdim && $conditionalhidden) {
 374                  $linkclasses .= ' conditionalhidden';
 375                  $textclasses .= ' conditionalhidden';
 376              }
 377          }
 378          $this->displayoptions['linkclasses'] = $linkclasses;
 379          $this->displayoptions['textclasses'] = $textclasses;
 380          $this->displayoptions['onclick'] = htmlspecialchars_decode($mod->onclick, ENT_QUOTES);;
 381      }
 382  
 383      /**
 384       * Get the activity link classes.
 385       *
 386       * @return string the activity link classes.
 387       */
 388      public function get_link_classes(): string {
 389          return $this->displayoptions['linkclasses'] ?? '';
 390      }
 391  
 392      /**
 393       * Get the activity text/description classes.
 394       *
 395       * @return string the activity text classes.
 396       */
 397      public function get_text_classes(): string {
 398          return $this->displayoptions['textclasses'] ?? '';
 399      }
 400  
 401      /**
 402       * Get the activity onclick code.
 403       *
 404       * @return string the activity onclick.
 405       */
 406      public function get_onclick_code(): string {
 407          return $this->displayoptions['onclick'];
 408      }
 409  }