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  
   3  // This file is part of Moodle - http://moodle.org/
   4  //
   5  // Moodle is free software: you can redistribute it and/or modify
   6  // it under the terms of the GNU General Public License as published by
   7  // the Free Software Foundation, either version 3 of the License, or
   8  // (at your option) any later version.
   9  //
  10  // Moodle is distributed in the hope that it will be useful,
  11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13  // GNU General Public License for more details.
  14  //
  15  // You should have received a copy of the GNU General Public License
  16  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  17  
  18  /**
  19   * @package   mod_forum
  20   * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  21   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   */
  23  
  24  require_once('../../config.php');
  25  require_once ('lib.php');
  26  
  27  $id = required_param('id', PARAM_INT);                  // course id
  28  $search = trim(optional_param('search', '', PARAM_NOTAGS));  // search string
  29  $page = optional_param('page', 0, PARAM_INT);   // which page to show
  30  $perpage = optional_param('perpage', 10, PARAM_INT);   // how many per page
  31  $showform = optional_param('showform', 0, PARAM_INT);   // Just show the form
  32  
  33  $user    = trim(optional_param('user', '', PARAM_NOTAGS));    // Names to search for
  34  $userid  = trim(optional_param('userid', 0, PARAM_INT));      // UserID to search for
  35  $forumid = trim(optional_param('forumid', 0, PARAM_INT));      // ForumID to search for
  36  $subject = trim(optional_param('subject', '', PARAM_NOTAGS)); // Subject
  37  $phrase  = trim(optional_param('phrase', '', PARAM_NOTAGS));  // Phrase
  38  $words   = trim(optional_param('words', '', PARAM_NOTAGS));   // Words
  39  $fullwords = trim(optional_param('fullwords', '', PARAM_NOTAGS)); // Whole words
  40  $notwords = trim(optional_param('notwords', '', PARAM_NOTAGS));   // Words we don't want
  41  $tags = optional_param_array('tags', [], PARAM_TEXT);
  42  
  43  $timefromrestrict = optional_param('timefromrestrict', 0, PARAM_INT); // Use starting date
  44  $fromday = optional_param('fromday', 0, PARAM_INT);      // Starting date
  45  $frommonth = optional_param('frommonth', 0, PARAM_INT);      // Starting date
  46  $fromyear = optional_param('fromyear', 0, PARAM_INT);      // Starting date
  47  $fromhour = optional_param('fromhour', 0, PARAM_INT);      // Starting date
  48  $fromminute = optional_param('fromminute', 0, PARAM_INT);      // Starting date
  49  if ($timefromrestrict) {
  50      $calendartype = \core_calendar\type_factory::get_calendar_instance();
  51      $gregorianfrom = $calendartype->convert_to_gregorian($fromyear, $frommonth, $fromday);
  52      $datefrom = make_timestamp($gregorianfrom['year'], $gregorianfrom['month'], $gregorianfrom['day'], $fromhour, $fromminute);
  53  } else {
  54      $datefrom = optional_param('datefrom', 0, PARAM_INT);      // Starting date
  55  }
  56  
  57  $timetorestrict = optional_param('timetorestrict', 0, PARAM_INT); // Use ending date
  58  $today = optional_param('today', 0, PARAM_INT);      // Ending date
  59  $tomonth = optional_param('tomonth', 0, PARAM_INT);      // Ending date
  60  $toyear = optional_param('toyear', 0, PARAM_INT);      // Ending date
  61  $tohour = optional_param('tohour', 0, PARAM_INT);      // Ending date
  62  $tominute = optional_param('tominute', 0, PARAM_INT);      // Ending date
  63  if ($timetorestrict) {
  64      $calendartype = \core_calendar\type_factory::get_calendar_instance();
  65      $gregorianto = $calendartype->convert_to_gregorian($toyear, $tomonth, $today);
  66      $dateto = make_timestamp($gregorianto['year'], $gregorianto['month'], $gregorianto['day'], $tohour, $tominute);
  67  } else {
  68      $dateto = optional_param('dateto', 0, PARAM_INT);      // Ending date
  69  }
  70  $starredonly = optional_param('starredonly', false, PARAM_BOOL); // Include only favourites.
  71  
  72  $PAGE->set_pagelayout('standard');
  73  $PAGE->set_url($FULLME); //TODO: this is very sloppy --skodak
  74  
  75  if (empty($search)) {   // Check the other parameters instead
  76      if (!empty($words)) {
  77          $search .= ' '.$words;
  78      }
  79      if (!empty($userid)) {
  80          $search .= ' userid:'.$userid;
  81      }
  82      if (!empty($forumid)) {
  83          $search .= ' forumid:'.$forumid;
  84      }
  85      if (!empty($user)) {
  86          $search .= ' '.forum_clean_search_terms($user, 'user:');
  87      }
  88      if (!empty($subject)) {
  89          $search .= ' '.forum_clean_search_terms($subject, 'subject:');
  90      }
  91      if (!empty($fullwords)) {
  92          $search .= ' '.forum_clean_search_terms($fullwords, '+');
  93      }
  94      if (!empty($notwords)) {
  95          $search .= ' '.forum_clean_search_terms($notwords, '-');
  96      }
  97      if (!empty($phrase)) {
  98          $search .= ' "'.$phrase.'"';
  99      }
 100      if (!empty($datefrom)) {
 101          $search .= ' datefrom:'.$datefrom;
 102      }
 103      if (!empty($dateto)) {
 104          $search .= ' dateto:'.$dateto;
 105      }
 106      if (!empty($tags)) {
 107          $search .= ' tags:' . implode(',', $tags);
 108      }
 109      if (!empty($starredonly)) {
 110          $search .= ' starredonly:on';
 111      }
 112      $individualparams = true;
 113  } else {
 114      $individualparams = false;
 115  }
 116  
 117  if ($search) {
 118      $search = forum_clean_search_terms($search);
 119  }
 120  
 121  if (!$course = $DB->get_record('course', array('id'=>$id))) {
 122      print_error('invalidcourseid');
 123  }
 124  
 125  require_course_login($course);
 126  
 127  $params = array(
 128      'context' => $PAGE->context,
 129      'other' => array('searchterm' => $search)
 130  );
 131  
 132  $event = \mod_forum\event\course_searched::create($params);
 133  $event->trigger();
 134  
 135  $strforums = get_string("modulenameplural", "forum");
 136  $strsearch = get_string("search", "forum");
 137  $strsearchresults = get_string("searchresults", "forum");
 138  $strpage = get_string("page");
 139  
 140  if (!$search || $showform) {
 141  
 142      $PAGE->navbar->add($strforums, new moodle_url('/mod/forum/index.php', array('id'=>$course->id)));
 143      $PAGE->navbar->add(get_string('advancedsearch', 'forum'));
 144  
 145      $PAGE->set_title($strsearch);
 146      $PAGE->set_heading($course->fullname);
 147      echo $OUTPUT->header();
 148  
 149      forum_print_big_search_form($course);
 150      echo $OUTPUT->footer();
 151      exit;
 152  }
 153  
 154  /// We need to do a search now and print results
 155  
 156  $searchterms = str_replace('forumid:', 'instance:', $search);
 157  $searchterms = explode(' ', $searchterms);
 158  
 159  $searchform = forum_search_form($course, $search);
 160  
 161  $PAGE->navbar->add($strsearch, new moodle_url('/mod/forum/search.php', array('id'=>$course->id)));
 162  $PAGE->navbar->add($strsearchresults);
 163  if (!$posts = forum_search_posts($searchterms, $course->id, $page*$perpage, $perpage, $totalcount)) {
 164      $PAGE->set_title($strsearchresults);
 165      $PAGE->set_heading($course->fullname);
 166      echo $OUTPUT->header();
 167      echo $OUTPUT->heading($strforums, 2);
 168      echo $OUTPUT->heading($strsearchresults, 3);
 169      echo $OUTPUT->heading(get_string("noposts", "forum"), 4);
 170  
 171      if (!$individualparams) {
 172          $words = $search;
 173      }
 174  
 175      forum_print_big_search_form($course);
 176  
 177      echo $OUTPUT->footer();
 178      exit;
 179  }
 180  
 181  //including this here to prevent it being included if there are no search results
 182  require_once($CFG->dirroot.'/rating/lib.php');
 183  
 184  //set up the ratings information that will be the same for all posts
 185  $ratingoptions = new stdClass();
 186  $ratingoptions->component = 'mod_forum';
 187  $ratingoptions->ratingarea = 'post';
 188  $ratingoptions->userid = $USER->id;
 189  $ratingoptions->returnurl = $PAGE->url->out(false);
 190  $rm = new rating_manager();
 191  
 192  $PAGE->set_title($strsearchresults);
 193  $PAGE->set_heading($course->fullname);
 194  $PAGE->set_button($searchform);
 195  echo $OUTPUT->header();
 196  echo '<div class="reportlink">';
 197  
 198  $params = [
 199      'id'        => $course->id,
 200      'user'      => $user,
 201      'userid'    => $userid,
 202      'forumid'   => $forumid,
 203      'subject'   => $subject,
 204      'phrase'    => $phrase,
 205      'words'     => $words,
 206      'fullwords' => $fullwords,
 207      'notwords'  => $notwords,
 208      'dateto'    => $dateto,
 209      'datefrom'  => $datefrom,
 210      'showform'  => 1,
 211      'starredonly' => $starredonly
 212  ];
 213  $url    = new moodle_url("/mod/forum/search.php", $params);
 214  foreach ($tags as $tag) {
 215      $url .= "&tags[]=$tag";
 216  }
 217  echo html_writer::link($url, get_string('advancedsearch', 'forum').'...');
 218  
 219  echo '</div>';
 220  
 221  echo $OUTPUT->heading($strforums, 2);
 222  echo $OUTPUT->heading("$strsearchresults: $totalcount", 3);
 223  
 224  $url = new moodle_url('search.php', array('search' => $search, 'id' => $course->id, 'perpage' => $perpage));
 225  echo $OUTPUT->paging_bar($totalcount, $page, $perpage, $url);
 226  
 227  //added to implement highlighting of search terms found only in HTML markup
 228  //fiedorow - 9/2/2005
 229  $strippedsearch = str_replace('user:','',$search);
 230  $strippedsearch = str_replace('subject:','',$strippedsearch);
 231  $strippedsearch = str_replace('&quot;','',$strippedsearch);
 232  $searchterms = explode(' ', $strippedsearch);    // Search for words independently
 233  foreach ($searchterms as $key => $searchterm) {
 234      if (preg_match('/^\-/',$searchterm)) {
 235          unset($searchterms[$key]);
 236      } else {
 237          $searchterms[$key] = preg_replace('/^\+/','',$searchterm);
 238      }
 239  }
 240  $strippedsearch = implode(' ', $searchterms);    // Rebuild the string
 241  $entityfactory = mod_forum\local\container::get_entity_factory();
 242  $vaultfactory = mod_forum\local\container::get_vault_factory();
 243  $rendererfactory = mod_forum\local\container::get_renderer_factory();
 244  $managerfactory = mod_forum\local\container::get_manager_factory();
 245  $legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory();
 246  $forumdatamapper = $legacydatamapperfactory->get_forum_data_mapper();
 247  
 248  $discussionvault = $vaultfactory->get_discussion_vault();
 249  $discussionids = array_keys(array_reduce($posts, function($carry, $post) {
 250      $carry[$post->discussion] = true;
 251      return $carry;
 252  }, []));
 253  $discussions = $discussionvault->get_from_ids($discussionids);
 254  $discussionsbyid = array_reduce($discussions, function($carry, $discussion) {
 255      $carry[$discussion->get_id()] = $discussion;
 256      return $carry;
 257  }, []);
 258  
 259  $forumvault = $vaultfactory->get_forum_vault();
 260  $forumids = array_keys(array_reduce($discussions, function($carry, $discussion) {
 261      $carry[$discussion->get_forum_id()] = true;
 262      return $carry;
 263  }, []));
 264  $forums = $forumvault->get_from_ids($forumids);
 265  $forumsbyid = array_reduce($forums, function($carry, $forum) {
 266      $carry[$forum->get_id()] = $forum;
 267      return $carry;
 268  }, []);
 269  
 270  $postids = array_map(function($post) {
 271      return $post->id;
 272  }, $posts);
 273  
 274  $poststorender = [];
 275  
 276  foreach ($posts as $post) {
 277  
 278      // Replace the simple subject with the three items forum name -> thread name -> subject
 279      // (if all three are appropriate) each as a link.
 280      if (!isset($discussionsbyid[$post->discussion])) {
 281          print_error('invaliddiscussionid', 'forum');
 282      }
 283  
 284      $discussion = $discussionsbyid[$post->discussion];
 285      if (!isset($forumsbyid[$discussion->get_forum_id()])) {
 286          print_error('invalidforumid', 'forum');
 287      }
 288  
 289      $forum = $forumsbyid[$discussion->get_forum_id()];
 290      $capabilitymanager = $managerfactory->get_capability_manager($forum);
 291      $postentity = $entityfactory->get_post_from_stdclass($post);
 292  
 293      if (!$capabilitymanager->can_view_post($USER, $discussion, $postentity)) {
 294          // Don't render posts that the user can't view.
 295          continue;
 296      }
 297  
 298      if ($postentity->is_deleted()) {
 299          // Don't render deleted posts.
 300          continue;
 301      }
 302  
 303      $poststorender[] = $postentity;
 304  }
 305  
 306  $renderer = $rendererfactory->get_posts_search_results_renderer($searchterms);
 307  echo $renderer->render(
 308      $USER,
 309      $forumsbyid,
 310      $discussionsbyid,
 311      $poststorender
 312  );
 313  
 314  echo $OUTPUT->paging_bar($totalcount, $page, $perpage, $url);
 315  
 316  echo $OUTPUT->footer();
 317  
 318  
 319   /**
 320    * Print a full-sized search form for the specified course.
 321    *
 322    * @param stdClass $course The Course that will be searched.
 323    * @return void The function prints the form.
 324    */
 325  function forum_print_big_search_form($course) {
 326      global $PAGE, $words, $subject, $phrase, $user, $fullwords, $notwords, $datefrom,
 327             $dateto, $forumid, $tags, $starredonly;
 328  
 329      $renderable = new \mod_forum\output\big_search_form($course, $user);
 330      $renderable->set_words($words);
 331      $renderable->set_phrase($phrase);
 332      $renderable->set_notwords($notwords);
 333      $renderable->set_fullwords($fullwords);
 334      $renderable->set_datefrom($datefrom);
 335      $renderable->set_dateto($dateto);
 336      $renderable->set_subject($subject);
 337      $renderable->set_user($user);
 338      $renderable->set_forumid($forumid);
 339      $renderable->set_tags($tags);
 340      $renderable->set_starredonly($starredonly);
 341  
 342      $output = $PAGE->get_renderer('mod_forum');
 343      echo $output->render($renderable);
 344  }
 345  
 346  /**
 347   * This function takes each word out of the search string, makes sure they are at least
 348   * two characters long and returns an string of the space-separated search
 349   * terms.
 350   *
 351   * @param string $words String containing space-separated strings to search for.
 352   * @param string $prefix String to prepend to the each token taken out of $words.
 353   * @return string The filtered search terms, separated by spaces.
 354   * @todo Take the hardcoded limit out of this function and put it into a user-specified parameter.
 355   */
 356  function forum_clean_search_terms($words, $prefix='') {
 357      $searchterms = explode(' ', $words);
 358      foreach ($searchterms as $key => $searchterm) {
 359          if (strlen($searchterm) < 2) {
 360              unset($searchterms[$key]);
 361          } else if ($prefix) {
 362              $searchterms[$key] = $prefix.$searchterm;
 363          }
 364      }
 365      return trim(implode(' ', $searchterms));
 366  }
 367  
 368   /**
 369    * Retrieve a list of the forums that this user can view.
 370    *
 371    * @param stdClass $course The Course to use.
 372    * @return array A set of formatted forum names stored against the forum id.
 373    */
 374  function forum_menu_list($course)  {
 375      $menu = array();
 376  
 377      $modinfo = get_fast_modinfo($course);
 378      if (empty($modinfo->instances['forum'])) {
 379          return $menu;
 380      }
 381  
 382      foreach ($modinfo->instances['forum'] as $cm) {
 383          if (!$cm->uservisible) {
 384              continue;
 385          }
 386          $context = context_module::instance($cm->id);
 387          if (!has_capability('mod/forum:viewdiscussion', $context)) {
 388              continue;
 389          }
 390          $menu[$cm->instance] = format_string($cm->name);
 391      }
 392  
 393      return $menu;
 394  }