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.
   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   * Search area for mod_wiki collaborative pages.
  19   *
  20   * @package    mod_wiki
  21   * @copyright  2016 Eric Merrill {@link http://www.merrilldigital.com}
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace mod_wiki\search;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  require_once($CFG->dirroot . '/mod/wiki/locallib.php');
  30  
  31  /**
  32   * Search area for mod_wiki collaborative pages.
  33   *
  34   * @package    mod_wiki
  35   * @copyright  2016 Eric Merrill {@link http://www.merrilldigital.com}
  36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class collaborative_page extends \core_search\base_mod {
  39      /**
  40       * @var array Cache of wiki records.
  41       */
  42      protected $wikiscache = array();
  43  
  44      /**
  45       * Returns a recordset with all required page information.
  46       *
  47       * @param int $modifiedfrom
  48       * @param \context|null $context Optional context to restrict scope of returned results
  49       * @return moodle_recordset|null Recordset (or null if no results)
  50       */
  51      public function get_document_recordset($modifiedfrom = 0, \context $context = null) {
  52          global $DB;
  53  
  54          list ($contextjoin, $contextparams) = $this->get_context_restriction_sql(
  55                  $context, 'wiki', 'w');
  56          if ($contextjoin === null) {
  57              return null;
  58          }
  59  
  60          $sql = "SELECT p.*, w.id AS wikiid, w.course AS courseid, s.groupid AS groupid
  61                    FROM {wiki_pages} p
  62                    JOIN {wiki_subwikis} s ON s.id = p.subwikiid
  63                    JOIN {wiki} w ON w.id = s.wikiid
  64            $contextjoin
  65                   WHERE p.timemodified >= ?
  66                     AND w.wikimode = ?
  67                ORDER BY p.timemodified ASC";
  68          return $DB->get_recordset_sql($sql, array_merge($contextparams,
  69                  [$modifiedfrom, 'collaborative']));
  70      }
  71  
  72      /**
  73       * Returns the document for a particular page.
  74       *
  75       * @param \stdClass $record A record containing, at least, the indexed document id and a modified timestamp
  76       * @param array     $options Options for document creation
  77       * @return \core_search\document
  78       */
  79      public function get_document($record, $options = array()) {
  80          try {
  81              $cm = $this->get_cm('wiki', $record->wikiid, $record->courseid);
  82              $context = \context_module::instance($cm->id);
  83          } catch (\dml_missing_record_exception $ex) {
  84              // Notify it as we run here as admin, we should see everything.
  85              debugging('Error retrieving ' . $this->areaid . ' ' . $record->id . ' document, not all required data is available: ' .
  86                  $ex->getMessage(), DEBUG_DEVELOPER);
  87              return false;
  88          } catch (\dml_exception $ex) {
  89              // Notify it as we run here as admin, we should see everything.
  90              debugging('Error retrieving ' . $this->areaid . ' ' . $record->id . ' document: ' . $ex->getMessage(), DEBUG_DEVELOPER);
  91              return false;
  92          }
  93  
  94          // Make a page object without extra fields.
  95          $page = clone $record;
  96          unset($page->courseid);
  97          unset($page->wikiid);
  98  
  99          // Conversion based wiki_print_page_content().
 100          // Check if we have passed the cache time.
 101          if ($page->timerendered + WIKI_REFRESH_CACHE_TIME < time()) {
 102              $content = wiki_refresh_cachedcontent($page);
 103              $page = $content['page'];
 104          }
 105          // Convert to text.
 106          $content = content_to_text($page->cachedcontent, FORMAT_MOODLE);
 107  
 108          // Prepare associative array with data from DB.
 109          $doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);
 110          $doc->set('title', content_to_text($record->title, false));
 111          $doc->set('content', $content);
 112          $doc->set('contextid', $context->id);
 113          $doc->set('courseid', $record->courseid);
 114          if ($record->groupid > 0) {
 115              $doc->set('groupid', $record->groupid);
 116          }
 117          $doc->set('owneruserid', \core_search\manager::NO_OWNER_ID);
 118          $doc->set('modified', $record->timemodified);
 119  
 120          // Check if this document should be considered new.
 121          if (isset($options['lastindexedtime']) && ($options['lastindexedtime'] < $record->timecreated)) {
 122              // If the document was created after the last index time, it must be new.
 123              $doc->set_is_new(true);
 124          }
 125  
 126          return $doc;
 127      }
 128  
 129      /**
 130       * Can the current user see the document.
 131       *
 132       * @param int $id The internal search area entity id.
 133       * @return bool True if the user can see it, false otherwise
 134       */
 135      public function check_access($id) {
 136          global $DB;
 137  
 138          try {
 139              $page = $DB->get_record('wiki_pages', array('id' => $id), '*', MUST_EXIST);
 140              if (!isset($this->wikiscache[$page->subwikiid])) {
 141                  $sql = 'SELECT w.*
 142                            FROM {wiki_subwikis} s
 143                            JOIN {wiki} w ON w.id = s.wikiid
 144                           WHERE s.id = ?';
 145                  $this->wikiscache[$page->subwikiid] = $DB->get_record_sql($sql, array('id' => $page->subwikiid), MUST_EXIST);
 146              }
 147              $wiki = $this->wikiscache[$page->subwikiid];
 148              $cminfo = $this->get_cm('wiki', $wiki->id, $wiki->course);
 149          } catch (\dml_missing_record_exception $ex) {
 150              return \core_search\manager::ACCESS_DELETED;
 151          } catch (\dml_exception $ex) {
 152              return \core_search\manager::ACCESS_DENIED;
 153          }
 154  
 155          // Recheck uservisible although it should have already been checked in core_search.
 156          if ($cminfo->uservisible === false) {
 157              return \core_search\manager::ACCESS_DENIED;
 158          }
 159  
 160          $context = \context_module::instance($cminfo->id);
 161  
 162          if (!has_capability('mod/wiki:viewpage', $context)) {
 163              return \core_search\manager::ACCESS_DENIED;
 164          }
 165  
 166          return \core_search\manager::ACCESS_GRANTED;
 167      }
 168  
 169      /**
 170       * Returns a url to the page.
 171       *
 172       * @param \core_search\document $doc
 173       * @return \moodle_url
 174       */
 175      public function get_doc_url(\core_search\document $doc) {
 176          $params = array('pageid' => $doc->get('itemid'));
 177          return new \moodle_url('/mod/wiki/view.php', $params);
 178      }
 179  
 180      /**
 181       * Returns a url to the wiki.
 182       *
 183       * @param \core_search\document $doc
 184       * @return \moodle_url
 185       */
 186      public function get_context_url(\core_search\document $doc) {
 187          $contextmodule = \context::instance_by_id($doc->get('contextid'));
 188          return new \moodle_url('/mod/wiki/view.php', array('id' => $contextmodule->instanceid));
 189      }
 190  
 191      /**
 192       * Returns true if this area uses file indexing.
 193       *
 194       * @return bool
 195       */
 196      public function uses_file_indexing() {
 197          return true;
 198      }
 199  
 200      /**
 201       * Return the context info required to index files for
 202       * this search area.
 203       *
 204       * @return array
 205       */
 206      public function get_search_fileareas() {
 207          $fileareas = array('attachments'); // Filearea.
 208  
 209          return $fileareas;
 210      }
 211  
 212      /**
 213       * Confirms that data entries support group restrictions.
 214       *
 215       * @return bool True
 216       */
 217      public function supports_group_restriction() {
 218          return true;
 219      }
 220  }