weekly release 3.8dev
[moodle.git] / mod / forum / search.php
CommitLineData
cd4e6b17 1<?php
2
8f685009
SH
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/**
01030f1b 19 * @package mod_forum
8f685009
SH
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
cd4e6b17 24require_once('../../config.php');
25require_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
d2ba493c 41$tags = optional_param_array('tags', [], PARAM_TEXT);
cd4e6b17 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
49if ($timefromrestrict) {
e83bcc10
SR
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);
cd4e6b17 53} else {
54 $datefrom = optional_param('datefrom', 0, PARAM_INT); // Starting date
55}
4e471fc6 56
cd4e6b17 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
63if ($timetorestrict) {
e83bcc10
SR
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);
cd4e6b17 67} else {
68 $dateto = optional_param('dateto', 0, PARAM_INT); // Ending date
69}
4e471fc6 70
267aff7f 71$PAGE->set_pagelayout('standard');
f0202ae9 72$PAGE->set_url($FULLME); //TODO: this is very sloppy --skodak
e6ae4dc8 73
cd4e6b17 74if (empty($search)) { // Check the other parameters instead
75 if (!empty($words)) {
76 $search .= ' '.$words;
e6ae4dc8 77 }
cd4e6b17 78 if (!empty($userid)) {
79 $search .= ' userid:'.$userid;
8b9c7aa0 80 }
cd4e6b17 81 if (!empty($forumid)) {
82 $search .= ' forumid:'.$forumid;
83 }
84 if (!empty($user)) {
85 $search .= ' '.forum_clean_search_terms($user, 'user:');
86 }
87 if (!empty($subject)) {
88 $search .= ' '.forum_clean_search_terms($subject, 'subject:');
89 }
90 if (!empty($fullwords)) {
91 $search .= ' '.forum_clean_search_terms($fullwords, '+');
92 }
93 if (!empty($notwords)) {
94 $search .= ' '.forum_clean_search_terms($notwords, '-');
501cdbd8 95 }
cd4e6b17 96 if (!empty($phrase)) {
97 $search .= ' "'.$phrase.'"';
98 }
99 if (!empty($datefrom)) {
100 $search .= ' datefrom:'.$datefrom;
101 }
102 if (!empty($dateto)) {
103 $search .= ' dateto:'.$dateto;
104 }
d2ba493c
AH
105 if (!empty($tags)) {
106 $search .= ' tags:' . implode(',', $tags);
107 }
cd4e6b17 108 $individualparams = true;
109} else {
110 $individualparams = false;
111}
501cdbd8 112
cd4e6b17 113if ($search) {
114 $search = forum_clean_search_terms($search);
115}
501cdbd8 116
cd4e6b17 117if (!$course = $DB->get_record('course', array('id'=>$id))) {
118 print_error('invalidcourseid');
119}
501cdbd8 120
cd4e6b17 121require_course_login($course);
97485d07 122
22881392
DP
123$params = array(
124 'context' => $PAGE->context,
125 'other' => array('searchterm' => $search)
126);
127
128$event = \mod_forum\event\course_searched::create($params);
129$event->trigger();
65bcf17b 130
cd4e6b17 131$strforums = get_string("modulenameplural", "forum");
132$strsearch = get_string("search", "forum");
133$strsearchresults = get_string("searchresults", "forum");
134$strpage = get_string("page");
65bcf17b 135
cd4e6b17 136if (!$search || $showform) {
680afe2e 137
a6855934 138 $PAGE->navbar->add($strforums, new moodle_url('/mod/forum/index.php', array('id'=>$course->id)));
b4c07395 139 $PAGE->navbar->add(get_string('advancedsearch', 'forum'));
501cdbd8 140
cd4e6b17 141 $PAGE->set_title($strsearch);
39790bd8 142 $PAGE->set_heading($course->fullname);
cd4e6b17 143 echo $OUTPUT->header();
e6ae4dc8 144
cd4e6b17 145 forum_print_big_search_form($course);
146 echo $OUTPUT->footer();
147 exit;
148}
e6ae4dc8 149
cd4e6b17 150/// We need to do a search now and print results
e6ae4dc8 151
cd4e6b17 152$searchterms = str_replace('forumid:', 'instance:', $search);
153$searchterms = explode(' ', $searchterms);
e6ae4dc8 154
cd4e6b17 155$searchform = forum_search_form($course, $search);
e6ae4dc8 156
a6855934 157$PAGE->navbar->add($strsearch, new moodle_url('/mod/forum/search.php', array('id'=>$course->id)));
b74c9a9f 158$PAGE->navbar->add($strsearchresults);
cd4e6b17 159if (!$posts = forum_search_posts($searchterms, $course->id, $page*$perpage, $perpage, $totalcount)) {
160 $PAGE->set_title($strsearchresults);
39790bd8 161 $PAGE->set_heading($course->fullname);
cd4e6b17 162 echo $OUTPUT->header();
66e2b9f8
AD
163 echo $OUTPUT->heading($strforums, 2);
164 echo $OUTPUT->heading($strsearchresults, 3);
165 echo $OUTPUT->heading(get_string("noposts", "forum"), 4);
77ffdf4b 166
cd4e6b17 167 if (!$individualparams) {
168 $words = $search;
e6ae4dc8 169 }
65bcf17b 170
cd4e6b17 171 forum_print_big_search_form($course);
172
173 echo $OUTPUT->footer();
174 exit;
175}
176
667f63fe
AD
177//including this here to prevent it being included if there are no search results
178require_once($CFG->dirroot.'/rating/lib.php');
179
180//set up the ratings information that will be the same for all posts
181$ratingoptions = new stdClass();
182$ratingoptions->component = 'mod_forum';
183$ratingoptions->ratingarea = 'post';
184$ratingoptions->userid = $USER->id;
185$ratingoptions->returnurl = $PAGE->url->out(false);
186$rm = new rating_manager();
187
cd4e6b17 188$PAGE->set_title($strsearchresults);
b4c07395 189$PAGE->set_heading($course->fullname);
cd4e6b17 190$PAGE->set_button($searchform);
191echo $OUTPUT->header();
192echo '<div class="reportlink">';
d2ba493c
AH
193
194$params = [
195 'id' => $course->id,
196 'user' => $user,
197 'userid' => $userid,
198 'forumid' => $forumid,
199 'subject' => $subject,
200 'phrase' => $phrase,
201 'words' => $words,
202 'fullwords' => $fullwords,
203 'notwords' => $notwords,
204 'dateto' => $dateto,
205 'datefrom' => $datefrom,
206 'showform' => 1
207];
208$url = new moodle_url("/mod/forum/search.php", $params);
209foreach ($tags as $tag) {
210 $url .= "&tags[]=$tag";
211}
212echo html_writer::link($url, get_string('advancedsearch', 'forum').'...');
213
cd4e6b17 214echo '</div>';
215
66e2b9f8
AD
216echo $OUTPUT->heading($strforums, 2);
217echo $OUTPUT->heading("$strsearchresults: $totalcount", 3);
cd4e6b17 218
1d67258e 219$url = new moodle_url('search.php', array('search' => $search, 'id' => $course->id, 'perpage' => $perpage));
929d7a83 220echo $OUTPUT->paging_bar($totalcount, $page, $perpage, $url);
cd4e6b17 221
222//added to implement highlighting of search terms found only in HTML markup
223//fiedorow - 9/2/2005
224$strippedsearch = str_replace('user:','',$search);
225$strippedsearch = str_replace('subject:','',$strippedsearch);
226$strippedsearch = str_replace('&quot;','',$strippedsearch);
227$searchterms = explode(' ', $strippedsearch); // Search for words independently
228foreach ($searchterms as $key => $searchterm) {
229 if (preg_match('/^\-/',$searchterm)) {
230 unset($searchterms[$key]);
231 } else {
232 $searchterms[$key] = preg_replace('/^\+/','',$searchterm);
e6ae4dc8 233 }
cd4e6b17 234}
235$strippedsearch = implode(' ', $searchterms); // Rebuild the string
aa99838d
RW
236$entityfactory = mod_forum\local\container::get_entity_factory();
237$vaultfactory = mod_forum\local\container::get_vault_factory();
238$rendererfactory = mod_forum\local\container::get_renderer_factory();
239$managerfactory = mod_forum\local\container::get_manager_factory();
240$legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory();
241$forumdatamapper = $legacydatamapperfactory->get_forum_data_mapper();
242
243$discussionvault = $vaultfactory->get_discussion_vault();
244$discussionids = array_keys(array_reduce($posts, function($carry, $post) {
245 $carry[$post->discussion] = true;
246 return $carry;
247}, []));
248$discussions = $discussionvault->get_from_ids($discussionids);
249$discussionsbyid = array_reduce($discussions, function($carry, $discussion) {
250 $carry[$discussion->get_id()] = $discussion;
251 return $carry;
252}, []);
253
254$forumvault = $vaultfactory->get_forum_vault();
255$forumids = array_keys(array_reduce($discussions, function($carry, $discussion) {
256 $carry[$discussion->get_forum_id()] = true;
257 return $carry;
258}, []));
259$forums = $forumvault->get_from_ids($forumids);
260$forumsbyid = array_reduce($forums, function($carry, $forum) {
261 $carry[$forum->get_id()] = $forum;
262 return $carry;
263}, []);
264
265$postids = array_map(function($post) {
266 return $post->id;
267}, $posts);
268
269$poststorender = [];
501cdbd8 270
cd4e6b17 271foreach ($posts as $post) {
e6ae4dc8 272
cd4e6b17 273 // Replace the simple subject with the three items forum name -> thread name -> subject
274 // (if all three are appropriate) each as a link.
aa99838d 275 if (!isset($discussionsbyid[$post->discussion])) {
cd4e6b17 276 print_error('invaliddiscussionid', 'forum');
277 }
501cdbd8 278
aa99838d
RW
279 $discussion = $discussionsbyid[$post->discussion];
280 if (!isset($forumsbyid[$discussion->get_forum_id()])) {
281 print_error('invalidforumid', 'forum');
cd4e6b17 282 }
501cdbd8 283
aa99838d
RW
284 $forum = $forumsbyid[$discussion->get_forum_id()];
285 $capabilitymanager = $managerfactory->get_capability_manager($forum);
286 $postentity = $entityfactory->get_post_from_stdclass($post);
5da8e7d5 287
aa99838d
RW
288 if (!$capabilitymanager->can_view_post($USER, $discussion, $postentity)) {
289 // Don't render posts that the user can't view.
290 continue;
cd4e6b17 291 }
b800ac5a 292
aa99838d
RW
293 if ($postentity->is_deleted()) {
294 // Don't render deleted posts.
295 continue;
34edbe57
JSM
296 }
297
aa99838d 298 $poststorender[] = $postentity;
cd4e6b17 299}
501cdbd8 300
aa99838d
RW
301$renderer = $rendererfactory->get_posts_search_results_renderer($searchterms);
302echo $renderer->render(
303 $USER,
304 $forumsbyid,
305 $discussionsbyid,
306 $poststorender
307);
308
929d7a83 309echo $OUTPUT->paging_bar($totalcount, $page, $perpage, $url);
e6ae4dc8 310
cd4e6b17 311echo $OUTPUT->footer();
501cdbd8 312
e6ae4dc8 313
3a4ff0a8
AN
314 /**
315 * Print a full-sized search form for the specified course.
316 *
d9b196d9 317 * @param stdClass $course The Course that will be searched.
3a4ff0a8
AN
318 * @return void The function prints the form.
319 */
e6ae4dc8 320function forum_print_big_search_form($course) {
d2ba493c 321 global $PAGE, $words, $subject, $phrase, $user, $fullwords, $notwords, $datefrom, $dateto, $forumid, $tags;
10deddd3
FM
322
323 $renderable = new \mod_forum\output\big_search_form($course, $user);
324 $renderable->set_words($words);
325 $renderable->set_phrase($phrase);
326 $renderable->set_notwords($notwords);
327 $renderable->set_fullwords($fullwords);
328 $renderable->set_datefrom($datefrom);
329 $renderable->set_dateto($dateto);
330 $renderable->set_subject($subject);
331 $renderable->set_user($user);
1da58a1a 332 $renderable->set_forumid($forumid);
d2ba493c 333 $renderable->set_tags($tags);
10deddd3
FM
334
335 $output = $PAGE->get_renderer('mod_forum');
336 echo $output->render($renderable);
e6ae4dc8 337}
338
e9ff8e10 339/**
65bcf17b 340 * This function takes each word out of the search string, makes sure they are at least
3a4ff0a8
AN
341 * two characters long and returns an string of the space-separated search
342 * terms.
65bcf17b 343 *
3a4ff0a8
AN
344 * @param string $words String containing space-separated strings to search for.
345 * @param string $prefix String to prepend to the each token taken out of $words.
346 * @return string The filtered search terms, separated by spaces.
347 * @todo Take the hardcoded limit out of this function and put it into a user-specified parameter.
e9ff8e10 348 */
e6ae4dc8 349function forum_clean_search_terms($words, $prefix='') {
350 $searchterms = explode(' ', $words);
351 foreach ($searchterms as $key => $searchterm) {
352 if (strlen($searchterm) < 2) {
353 unset($searchterms[$key]);
354 } else if ($prefix) {
355 $searchterms[$key] = $prefix.$searchterm;
356 }
357 }
358 return trim(implode(' ', $searchterms));
359}
360
3a4ff0a8
AN
361 /**
362 * Retrieve a list of the forums that this user can view.
363 *
d9b196d9 364 * @param stdClass $course The Course to use.
3a4ff0a8
AN
365 * @return array A set of formatted forum names stored against the forum id.
366 */
77ffdf4b 367function forum_menu_list($course) {
77ffdf4b 368 $menu = array();
77ffdf4b 369
debd3d62 370 $modinfo = get_fast_modinfo($course);
debd3d62 371 if (empty($modinfo->instances['forum'])) {
372 return $menu;
373 }
374
375 foreach ($modinfo->instances['forum'] as $cm) {
376 if (!$cm->uservisible) {
377 continue;
378 }
bf0f06b1 379 $context = context_module::instance($cm->id);
debd3d62 380 if (!has_capability('mod/forum:viewdiscussion', $context)) {
381 continue;
77ffdf4b 382 }
debd3d62 383 $menu[$cm->instance] = format_string($cm->name);
77ffdf4b 384 }
385
386 return $menu;
387}