Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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