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 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]

   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 class content_item_repository, for fetching content_items.
  19   *
  20   * @package    core
  21   * @subpackage course
  22   * @copyright  2020 Jake Dallimore <jrhdallimore@gmail.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  namespace core_course\local\repository;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  use core_component;
  30  use core_course\local\entity\content_item;
  31  use core_course\local\entity\lang_string_title;
  32  use core_course\local\entity\string_title;
  33  
  34  /**
  35   * The class content_item_repository, for reading content_items.
  36   *
  37   * @copyright  2020 Jake Dallimore <jrhdallimore@gmail.com>
  38   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   */
  40  class content_item_readonly_repository implements content_item_readonly_repository_interface {
  41      /**
  42       * Get the help string for content items representing core modules.
  43       *
  44       * @param string $modname the module name.
  45       * @return string the help string, including help link.
  46       */
  47      private function get_core_module_help_string(string $modname): string {
  48          global $OUTPUT;
  49  
  50          $help = '';
  51          $sm = get_string_manager();
  52          if ($sm->string_exists('modulename_help', $modname)) {
  53              $help = get_string('modulename_help', $modname);
  54              if ($sm->string_exists('modulename_link', $modname)) { // Link to further info in Moodle docs.
  55                  $link = get_string('modulename_link', $modname);
  56                  $linktext = get_string('morehelp');
  57                  $arialabel = get_string('morehelpaboutmodule', '', get_string('modulename', $modname));
  58                  $doclink = $OUTPUT->doc_link($link, $linktext, true, ['aria-label' => $arialabel]);
  59                  $help .= \html_writer::tag('div', $doclink, ['class' => 'helpdoclink']);
  60              }
  61          }
  62          return $help;
  63      }
  64  
  65      /**
  66       * Helper to get the contentitems from all subplugin hooks for a given module plugin.
  67       *
  68       * @param string $parentpluginname the name of the module plugin to check subplugins for.
  69       * @param content_item $modulecontentitem the content item of the module plugin, to pass to the hooks.
  70       * @param \stdClass $user the user object to pass to subplugins.
  71       * @return array the array of content items.
  72       */
  73      private function get_subplugin_course_content_items(string $parentpluginname, content_item $modulecontentitem,
  74              \stdClass $user): array {
  75  
  76          $contentitems = [];
  77          $pluginmanager = \core_plugin_manager::instance();
  78          foreach ($pluginmanager->get_subplugins_of_plugin($parentpluginname) as $subpluginname => $subplugin) {
  79              // Call the hook, but with a copy of the module content item data.
  80              $spcontentitems = component_callback($subpluginname, 'get_course_content_items', [$modulecontentitem, $user], null);
  81              if (!is_null($spcontentitems)) {
  82                  foreach ($spcontentitems as $spcontentitem) {
  83                      $contentitems[] = $spcontentitem;
  84                  }
  85              }
  86          }
  87          return $contentitems;
  88      }
  89  
  90      /**
  91       * Get all the content items for a subplugin.
  92       *
  93       * @param string $parentpluginname
  94       * @param content_item $modulecontentitem
  95       * @return array
  96       */
  97      private function get_subplugin_all_content_items(string $parentpluginname, content_item $modulecontentitem): array {
  98          $contentitems = [];
  99          $pluginmanager = \core_plugin_manager::instance();
 100          foreach ($pluginmanager->get_subplugins_of_plugin($parentpluginname) as $subpluginname => $subplugin) {
 101              // Call the hook, but with a copy of the module content item data.
 102              $spcontentitems = component_callback($subpluginname, 'get_all_content_items', [$modulecontentitem], null);
 103              if (!is_null($spcontentitems)) {
 104                  foreach ($spcontentitems as $spcontentitem) {
 105                      $contentitems[] = $spcontentitem;
 106                  }
 107              }
 108          }
 109          return $contentitems;
 110      }
 111  
 112      /**
 113       * Find all the available content items, not restricted to course or user.
 114       *
 115       * @return array the array of content items.
 116       */
 117      public function find_all(): array {
 118          global $OUTPUT, $DB, $CFG;
 119  
 120          // Get all modules so we know which plugins are enabled and able to add content.
 121          // Only module plugins may add content items.
 122          $modules = $DB->get_records('modules', ['visible' => 1]);
 123          $return = [];
 124  
 125          // Now, generate the content_items.
 126          foreach ($modules as $modid => $mod) {
 127              // Exclude modules if the code doesn't exist.
 128              if (!file_exists("$CFG->dirroot/mod/$mod->name/lib.php")) {
 129                  continue;
 130              }
 131              // Create the content item for the module itself.
 132              // If the module chooses to implement the hook, this may be thrown away.
 133              $help = $this->get_core_module_help_string($mod->name);
 134              $archetype = plugin_supports('mod', $mod->name, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
 135              $purpose = plugin_supports('mod', $mod->name, FEATURE_MOD_PURPOSE, MOD_PURPOSE_OTHER);
 136  
 137              $contentitem = new content_item(
 138                  $mod->id,
 139                  $mod->name,
 140                  new lang_string_title("modulename", $mod->name),
 141                  new \moodle_url(''), // No course scope, so just an empty link.
 142                  $OUTPUT->pix_icon('monologo', '', $mod->name, ['class' => 'icon activityicon']),
 143                  $help,
 144                  $archetype,
 145                  'mod_' . $mod->name,
 146                  $purpose,
 147              );
 148  
 149              $modcontentitemreference = clone($contentitem);
 150  
 151              if (component_callback_exists('mod_' . $mod->name, 'get_all_content_items')) {
 152                  // Call the module hooks for this module.
 153                  $plugincontentitems = component_callback('mod_' . $mod->name, 'get_all_content_items',
 154                      [$modcontentitemreference], []);
 155                  if (!empty($plugincontentitems)) {
 156                      array_push($return, ...$plugincontentitems);
 157                  }
 158  
 159                  // Now, get those for subplugins of the module.
 160                  $subplugincontentitems = $this->get_subplugin_all_content_items('mod_' . $mod->name, $modcontentitemreference);
 161                  if (!empty($subplugincontentitems)) {
 162                      array_push($return, ...$subplugincontentitems);
 163                  }
 164              } else {
 165                  // Neither callback was found, so just use the default module content item.
 166                  $return[] = $contentitem;
 167              }
 168          }
 169          return $return;
 170      }
 171  
 172      /**
 173       * Get the list of potential content items for the given course.
 174       *
 175       * @param \stdClass $course the course
 176       * @param \stdClass $user the user, to pass to plugins implementing callbacks.
 177       * @return array the array of content_item objects
 178       */
 179      public function find_all_for_course(\stdClass $course, \stdClass $user): array {
 180          global $OUTPUT, $DB, $CFG;
 181  
 182          // Get all modules so we know which plugins are enabled and able to add content.
 183          // Only module plugins may add content items.
 184          $modules = $DB->get_records('modules', ['visible' => 1]);
 185          $return = [];
 186  
 187          // Now, generate the content_items.
 188          foreach ($modules as $modid => $mod) {
 189              // Exclude modules if the code doesn't exist.
 190              if (!file_exists("$CFG->dirroot/mod/$mod->name/lib.php")) {
 191                  continue;
 192              }
 193              // Create the content item for the module itself.
 194              // If the module chooses to implement the hook, this may be thrown away.
 195              $help = $this->get_core_module_help_string($mod->name);
 196              $archetype = plugin_supports('mod', $mod->name, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
 197              $purpose = plugin_supports('mod', $mod->name, FEATURE_MOD_PURPOSE, MOD_PURPOSE_OTHER);
 198  
 199              $icon = 'monologo';
 200              // Quick check for monologo icons.
 201              // Plugins that don't have monologo icons will be displayed as is and CSS filter will not be applied.
 202              $hasmonologoicons = core_component::has_monologo_icon('mod', $mod->name);
 203              $iconclass = '';
 204              if (!$hasmonologoicons) {
 205                  $iconclass = 'nofilter';
 206              }
 207              $contentitem = new content_item(
 208                  $mod->id,
 209                  $mod->name,
 210                  new lang_string_title("modulename", $mod->name),
 211                  new \moodle_url('/course/mod.php', ['id' => $course->id, 'add' => $mod->name]),
 212                  $OUTPUT->pix_icon($icon, '', $mod->name, ['class' => "activityicon $iconclass"]),
 213                  $help,
 214                  $archetype,
 215                  'mod_' . $mod->name,
 216                  $purpose,
 217              );
 218  
 219              $modcontentitemreference = clone($contentitem);
 220  
 221              if (component_callback_exists('mod_' . $mod->name, 'get_course_content_items')) {
 222                  // Call the module hooks for this module.
 223                  $plugincontentitems = component_callback('mod_' . $mod->name, 'get_course_content_items',
 224                      [$modcontentitemreference, $user, $course], []);
 225                  if (!empty($plugincontentitems)) {
 226                      array_push($return, ...$plugincontentitems);
 227                  }
 228  
 229                  // Now, get those for subplugins of the module.
 230                  $subpluginitems = $this->get_subplugin_course_content_items('mod_' . $mod->name, $modcontentitemreference, $user);
 231                  if (!empty($subpluginitems)) {
 232                      array_push($return, ...$subpluginitems);
 233                  }
 234  
 235              } else {
 236                  // Callback was not found, so just use the default module content item.
 237                  $return[] = $contentitem;
 238              }
 239          }
 240  
 241          return $return;
 242      }
 243  }