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 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [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   * Glossary Random block.
  19   *
  20   * @package   block_glossary_random
  21   * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  define('BGR_RANDOMLY',     '0');
  26  define('BGR_LASTMODIFIED', '1');
  27  define('BGR_NEXTONE',      '2');
  28  define('BGR_NEXTALPHA',    '3');
  29  
  30  class block_glossary_random extends block_base {
  31  
  32      /**
  33       * @var cm_info|stdClass has properties 'id' (course module id) and 'uservisible'
  34       *     (whether the glossary is visible to the current user)
  35       */
  36      protected $glossarycm = null;
  37  
  38      /** @var stdClass course data. */
  39      public $course;
  40  
  41      function init() {
  42          $this->title = get_string('pluginname','block_glossary_random');
  43      }
  44  
  45      function specialization() {
  46          global $CFG, $DB;
  47  
  48          require_once($CFG->libdir . '/filelib.php');
  49  
  50          $this->course = $this->page->course;
  51  
  52          // load userdefined title and make sure it's never empty
  53          if (empty($this->config->title)) {
  54              $this->title = get_string('pluginname','block_glossary_random');
  55          } else {
  56              $this->title = format_string($this->config->title, true, ['context' => $this->context]);
  57          }
  58  
  59          if (empty($this->config->glossary)) {
  60              return false;
  61          }
  62  
  63          if (!isset($this->config->nexttime)) {
  64              $this->config->nexttime = 0;
  65          }
  66  
  67          //check if it's time to put a new entry in cache
  68          if (time() > $this->config->nexttime) {
  69  
  70              if (!($cm = $this->get_glossary_cm()) || !$cm->uservisible) {
  71                  // Skip generating of the cache if we can't display anything to the current user.
  72                  return false;
  73              }
  74  
  75              // place glossary concept and definition in $pref->cache
  76              if (!$numberofentries = $DB->count_records('glossary_entries',
  77                                                         array('glossaryid'=>$this->config->glossary, 'approved'=>1))) {
  78                  $this->config->cache = get_string('noentriesyet','block_glossary_random');
  79                  $this->instance_config_commit();
  80              }
  81  
  82              $glossaryctx = context_module::instance($cm->id);
  83  
  84              $limitfrom = 0;
  85              $limitnum = 1;
  86  
  87              $orderby = 'timemodified ASC';
  88  
  89              switch ($this->config->type) {
  90  
  91                  case BGR_RANDOMLY:
  92                      $i = ($numberofentries > 1) ? rand(1, $numberofentries) : 1;
  93                      $limitfrom = $i-1;
  94                      break;
  95  
  96                  case BGR_NEXTONE:
  97                      if (isset($this->config->previous)) {
  98                          $i = $this->config->previous + 1;
  99                      } else {
 100                          $i = 1;
 101                      }
 102                      if ($i > $numberofentries) {  // Loop back to beginning
 103                          $i = 1;
 104                      }
 105                      $limitfrom = $i-1;
 106                      break;
 107  
 108                  case BGR_NEXTALPHA:
 109                      $orderby = 'concept ASC';
 110                      if (isset($this->config->previous)) {
 111                          $i = $this->config->previous + 1;
 112                      } else {
 113                          $i = 1;
 114                      }
 115                      if ($i > $numberofentries) {  // Loop back to beginning
 116                          $i = 1;
 117                      }
 118                      $limitfrom = $i-1;
 119                      break;
 120  
 121                  default:  // BGR_LASTMODIFIED
 122                      $i = $numberofentries;
 123                      $limitfrom = 0;
 124                      $orderby = 'timemodified DESC, id DESC';
 125                      break;
 126              }
 127  
 128              if ($entry = $DB->get_records_sql("SELECT id, concept, definition, definitionformat, definitiontrust
 129                                                   FROM {glossary_entries}
 130                                                  WHERE glossaryid = ? AND approved = 1
 131                                               ORDER BY $orderby", array($this->config->glossary), $limitfrom, $limitnum)) {
 132  
 133                  $entry = reset($entry);
 134  
 135                  if (empty($this->config->showconcept)) {
 136                      $text = '';
 137                  } else {
 138                      $text = "<h3>".format_string($entry->concept,true)."</h3>";
 139                  }
 140  
 141                  $options = new stdClass();
 142                  $options->trusted = $entry->definitiontrust;
 143                  $options->overflowdiv = true;
 144                  $entry->definition = file_rewrite_pluginfile_urls($entry->definition, 'pluginfile.php', $glossaryctx->id, 'mod_glossary', 'entry', $entry->id);
 145                  $text .= format_text($entry->definition, $entry->definitionformat, $options);
 146  
 147                  $this->config->nexttime = usergetmidnight(time()) + DAYSECS * $this->config->refresh;
 148                  $this->config->previous = $i;
 149  
 150              } else {
 151                  $text = get_string('noentriesyet','block_glossary_random');
 152              }
 153              // store the text
 154              $this->config->cache = $text;
 155              $this->instance_config_commit();
 156          }
 157      }
 158  
 159      /**
 160       * Replace the instance's configuration data with those currently in $this->config;
 161       */
 162      function instance_config_commit($nolongerused = false) {
 163          // Unset config variables that are no longer used.
 164          unset($this->config->globalglossary);
 165          unset($this->config->courseid);
 166          parent::instance_config_commit($nolongerused);
 167      }
 168  
 169      /**
 170       * Checks if glossary is available - it should be either located in the same course or be global
 171       *
 172       * @return null|cm_info|stdClass object with properties 'id' (course module id) and 'uservisible'
 173       */
 174      protected function get_glossary_cm() {
 175          global $DB;
 176          if (empty($this->config->glossary)) {
 177              // No glossary is configured.
 178              return null;
 179          }
 180  
 181          if (!empty($this->glossarycm)) {
 182              return $this->glossarycm;
 183          }
 184  
 185          if (!empty($this->page->course->id)) {
 186              // First check if glossary belongs to the current course (we don't need to make any DB queries to find it).
 187              $modinfo = get_fast_modinfo($this->page->course);
 188              if (isset($modinfo->instances['glossary'][$this->config->glossary])) {
 189                  $this->glossarycm = $modinfo->instances['glossary'][$this->config->glossary];
 190                  if ($this->glossarycm->uservisible) {
 191                      // The glossary is in the same course and is already visible to the current user,
 192                      // no need to check if it is global, save on DB query.
 193                      return $this->glossarycm;
 194                  }
 195              }
 196          }
 197  
 198          // Find course module id for the given glossary, only if it is global.
 199          $cm = $DB->get_record_sql("SELECT cm.id, cm.visible AS uservisible
 200                FROM {course_modules} cm
 201                     JOIN {modules} md ON md.id = cm.module
 202                     JOIN {glossary} g ON g.id = cm.instance
 203               WHERE g.id = :instance AND md.name = :modulename AND g.globalglossary = 1",
 204              ['instance' => $this->config->glossary, 'modulename' => 'glossary']);
 205  
 206          if ($cm) {
 207              // This is a global glossary, create an object with properties 'id' and 'uservisible'. We don't need any
 208              // other information so why bother retrieving it. Full access check is skipped for global glossaries for
 209              // performance reasons.
 210              $this->glossarycm = $cm;
 211          } else if (empty($this->glossarycm)) {
 212              // Glossary does not exist. Remove it in the config so we don't repeat this check again later.
 213              $this->config->glossary = 0;
 214              $this->instance_config_commit();
 215          }
 216  
 217          return $this->glossarycm;
 218      }
 219  
 220      function instance_allow_multiple() {
 221      // Are you going to allow multiple instances of each block?
 222      // If yes, then it is assumed that the block WILL USE per-instance configuration
 223          return true;
 224      }
 225  
 226      function get_content() {
 227          if ($this->content !== null) {
 228              return $this->content;
 229          }
 230          $this->content = (object)['text' => '', 'footer' => ''];
 231  
 232          if (!$cm = $this->get_glossary_cm()) {
 233              if ($this->user_can_edit()) {
 234                  $this->content->text = get_string('notyetconfigured', 'block_glossary_random');
 235              }
 236              return $this->content;
 237          }
 238  
 239          if (empty($this->config->cache)) {
 240              $this->config->cache = '';
 241          }
 242  
 243          if ($cm->uservisible) {
 244              // Show glossary if visible and place links in footer.
 245              $this->content->text = $this->config->cache;
 246              if (has_capability('mod/glossary:write', context_module::instance($cm->id))) {
 247                  $this->content->footer = html_writer::link(new moodle_url('/mod/glossary/edit.php', ['cmid' => $cm->id]),
 248                      format_string($this->config->addentry)) . '<br/>';
 249              }
 250  
 251              $this->content->footer .= html_writer::link(new moodle_url('/mod/glossary/view.php', ['id' => $cm->id]),
 252                  format_string($this->config->viewglossary));
 253          } else {
 254              // Otherwise just place some text, no link.
 255              $this->content->footer = format_string($this->config->invisible);
 256          }
 257  
 258          return $this->content;
 259      }
 260  
 261      /**
 262       * Return the plugin config settings for external functions.
 263       *
 264       * @return stdClass the configs for both the block instance and plugin
 265       * @since Moodle 3.8
 266       */
 267      public function get_config_for_external() {
 268          // Return all settings for all users since it is safe (no private keys, etc..).
 269          $configs = !empty($this->config) ? $this->config : new stdClass();
 270  
 271          return (object) [
 272              'instance' => $configs,
 273              'plugin' => new stdClass(),
 274          ];
 275      }
 276  
 277      /**
 278       * This block shouldn't be added to a page if the glossary module is disabled.
 279       *
 280       * @param moodle_page $page
 281       * @return bool
 282       */
 283      public function can_block_be_added(moodle_page $page): bool {
 284          $pluginclass = \core_plugin_manager::resolve_plugininfo_class('mod');
 285          return $pluginclass::get_enabled_plugin('glossary');
 286      }
 287  }