Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

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