Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
   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 entries search.
  19   *
  20   * @package    mod_glossary
  21   * @copyright  2015 David Monllao {@link http://www.davidmonllao.com}
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace mod_glossary\search;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  require_once($CFG->dirroot . '/mod/glossary/lib.php');
  30  
  31  /**
  32   * Glossary entries search.
  33   *
  34   * @package    mod_glossary
  35   * @copyright  2015 David Monllao {@link http://www.davidmonllao.com}
  36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class entry extends \core_search\base_mod {
  39  
  40      /**
  41       * @var array Internal quick static cache.
  42       */
  43      protected $entriesdata = array();
  44  
  45      /**
  46       * Returns recordset containing required data for indexing glossary entries.
  47       *
  48       * @param int $modifiedfrom timestamp
  49       * @param \context|null $context Optional context to restrict scope of returned results
  50       * @return moodle_recordset|null Recordset (or null if no results)
  51       */
  52      public function get_document_recordset($modifiedfrom = 0, \context $context = null) {
  53          global $DB;
  54  
  55          list ($contextjoin, $contextparams) = $this->get_context_restriction_sql(
  56                  $context, 'glossary', 'g');
  57          if ($contextjoin === null) {
  58              return null;
  59          }
  60  
  61          $sql = "SELECT ge.*, g.course FROM {glossary_entries} ge
  62                    JOIN {glossary} g ON g.id = ge.glossaryid
  63            $contextjoin
  64                   WHERE ge.timemodified >= ? ORDER BY ge.timemodified ASC";
  65          return $DB->get_recordset_sql($sql, array_merge($contextparams, [$modifiedfrom]));
  66      }
  67  
  68      /**
  69       * Returns the documents associated with this glossary entry id.
  70       *
  71       * @param stdClass $entry glossary entry.
  72       * @param array    $options
  73       * @return \core_search\document
  74       */
  75      public function get_document($entry, $options = array()) {
  76          global $DB;
  77  
  78          $keywords = array();
  79          if ($aliases = $DB->get_records('glossary_alias', array('entryid' => $entry->id))) {
  80              foreach ($aliases as $alias) {
  81                  $keywords[] = $alias->alias;
  82              }
  83          }
  84  
  85          try {
  86              $cm = $this->get_cm('glossary', $entry->glossaryid, $entry->course);
  87              $context = \context_module::instance($cm->id);
  88          } catch (\dml_missing_record_exception $ex) {
  89              // Notify it as we run here as admin, we should see everything.
  90              debugging('Error retrieving mod_glossary ' . $entry->id . ' document, not all required data is available: ' .
  91                  $ex->getMessage(), DEBUG_DEVELOPER);
  92              return false;
  93          } catch (\dml_exception $ex) {
  94              // Notify it as we run here as admin, we should see everything.
  95              debugging('Error retrieving mod_glossary' . $entry->id . ' document: ' . $ex->getMessage(), DEBUG_DEVELOPER);
  96              return false;
  97          }
  98  
  99          // Prepare associative array with data from DB.
 100          $doc = \core_search\document_factory::instance($entry->id, $this->componentname, $this->areaname);
 101          $doc->set('title', content_to_text($entry->concept, false));
 102          $doc->set('content', content_to_text($entry->definition, $entry->definitionformat));
 103          $doc->set('contextid', $context->id);
 104          $doc->set('courseid', $entry->course);
 105          $doc->set('userid', $entry->userid);
 106          $doc->set('owneruserid', \core_search\manager::NO_OWNER_ID);
 107          $doc->set('modified', $entry->timemodified);
 108  
 109          // Check if this document should be considered new.
 110          if (isset($options['lastindexedtime']) && ($options['lastindexedtime'] < $entry->timecreated)) {
 111              // If the document was created after the last index time, it must be new.
 112              $doc->set_is_new(true);
 113          }
 114  
 115          // Adding keywords as extra info.
 116          if ($keywords) {
 117              // No need to pass through content_to_text here as this is just a list of keywords.
 118              $doc->set('description1', implode(' ' , $keywords));
 119          }
 120  
 121          return $doc;
 122      }
 123  
 124      /**
 125       * Whether the user can access the document or not.
 126       *
 127       * @throws \dml_missing_record_exception
 128       * @throws \dml_exception
 129       * @param int $id Glossary entry id
 130       * @return bool
 131       */
 132      public function check_access($id) {
 133          global $USER;
 134  
 135          try {
 136              $entry = $this->get_entry($id);
 137              $cminfo = $this->get_cm('glossary', $entry->glossaryid, $entry->course);
 138          } catch (\dml_missing_record_exception $ex) {
 139              return \core_search\manager::ACCESS_DELETED;
 140          } catch (\dml_exception $ex) {
 141              return \core_search\manager::ACCESS_DENIED;
 142          }
 143  
 144          if (!glossary_can_view_entry($entry, $cminfo)) {
 145              return \core_search\manager::ACCESS_DENIED;
 146          }
 147  
 148          return \core_search\manager::ACCESS_GRANTED;
 149      }
 150  
 151      /**
 152       * Link to glossary entry.
 153       *
 154       * @param \core_search\document $doc
 155       * @return \moodle_url
 156       */
 157      public function get_doc_url(\core_search\document $doc) {
 158          global $USER;
 159  
 160          // The post is already in static cache, we fetch it in self::search_access.
 161          $entry = $this->get_entry($doc->get('itemid'));
 162          $contextmodule = \context::instance_by_id($doc->get('contextid'));
 163  
 164          if ($entry->approved == false && $entry->userid != $USER->id) {
 165              // The URL should change when the entry is not approved and it was not created by the user.
 166              $docparams = array('id' => $contextmodule->instanceid, 'mode' => 'approval');
 167          } else {
 168              $docparams = array('id' => $contextmodule->instanceid, 'mode' => 'entry', 'hook' => $doc->get('itemid'));
 169  
 170          }
 171          return new \moodle_url('/mod/glossary/view.php', $docparams);
 172      }
 173  
 174      /**
 175       * Link to the glossary.
 176       *
 177       * @param \core_search\document $doc
 178       * @return \moodle_url
 179       */
 180      public function get_context_url(\core_search\document $doc) {
 181          $contextmodule = \context::instance_by_id($doc->get('contextid'));
 182          return new \moodle_url('/mod/glossary/view.php', array('id' => $contextmodule->instanceid));
 183      }
 184  
 185      /**
 186       * Returns the specified glossary entry checking the internal cache.
 187       *
 188       * Store minimal information as this might grow.
 189       *
 190       * @throws \dml_exception
 191       * @param int $entryid
 192       * @return stdClass
 193       */
 194      protected function get_entry($entryid) {
 195          global $DB;
 196  
 197          if (empty($this->entriesdata[$entryid])) {
 198              $this->entriesdata[$entryid] = $DB->get_record_sql("SELECT ge.*, g.course, g.defaultapproval FROM {glossary_entries} ge
 199                                                                    JOIN {glossary} g ON g.id = ge.glossaryid
 200                                                                  WHERE ge.id = ?", array('id' => $entryid), MUST_EXIST);
 201          }
 202          return $this->entriesdata[$entryid];
 203      }
 204  
 205      /**
 206       * Returns true if this area uses file indexing.
 207       *
 208       * @return bool
 209       */
 210      public function uses_file_indexing() {
 211          return true;
 212      }
 213  
 214      /**
 215       * Return the context info required to index files for
 216       * this search area.
 217       *
 218       * @return array
 219       */
 220      public function get_search_fileareas() {
 221          $fileareas = array('attachment', 'entry'); // Fileareas.
 222  
 223          return $fileareas;
 224      }
 225  }