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