weekly release 4.0dev
[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}
dd223096 70$starredonly = optional_param('starredonly', false, PARAM_BOOL); // Include only favourites.
4e471fc6 71
267aff7f 72$PAGE->set_pagelayout('standard');
f0202ae9 73$PAGE->set_url($FULLME); //TODO: this is very sloppy --skodak
e6ae4dc8 74
cd4e6b17 75if (empty($search)) { // Check the other parameters instead
76 if (!empty($words)) {
77 $search .= ' '.$words;
e6ae4dc8 78 }
cd4e6b17 79 if (!empty($userid)) {
80 $search .= ' userid:'.$userid;
8b9c7aa0 81 }
cd4e6b17 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, '-');
501cdbd8 96 }
cd4e6b17 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 }
d2ba493c
AH
106 if (!empty($tags)) {
107 $search .= ' tags:' . implode(',', $tags);
108 }
dd223096
P
109 if (!empty($starredonly)) {
110 $search .= ' starredonly:on';
111 }
cd4e6b17 112 $individualparams = true;
113} else {
114 $individualparams = false;
115}
501cdbd8 116
cd4e6b17 117if ($search) {
118 $search = forum_clean_search_terms($search);
119}
501cdbd8 120
cd4e6b17 121if (!$course = $DB->get_record('course', array('id'=>$id))) {
122 print_error('invalidcourseid');
123}
501cdbd8 124
cd4e6b17 125require_course_login($course);
97485d07 126
22881392
DP
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();
65bcf17b 134
cd4e6b17 135$strforums = get_string("modulenameplural", "forum");
136$strsearch = get_string("search", "forum");
137$strsearchresults = get_string("searchresults", "forum");
138$strpage = get_string("page");
65bcf17b 139
cd4e6b17 140if (!$search || $showform) {
680afe2e 141
a6855934 142 $PAGE->navbar->add($strforums, new moodle_url('/mod/forum/index.php', array('id'=>$course->id)));
b4c07395 143 $PAGE->navbar->add(get_string('advancedsearch', 'forum'));
501cdbd8 144
cd4e6b17 145 $PAGE->set_title($strsearch);
39790bd8 146 $PAGE->set_heading($course->fullname);
cd4e6b17 147 echo $OUTPUT->header();
e6ae4dc8 148
cd4e6b17 149 forum_print_big_search_form($course);
150 echo $OUTPUT->footer();
151 exit;
152}
e6ae4dc8 153
cd4e6b17 154/// We need to do a search now and print results
e6ae4dc8 155
cd4e6b17 156$searchterms = str_replace('forumid:', 'instance:', $search);
157$searchterms = explode(' ', $searchterms);
e6ae4dc8 158
cd4e6b17 159$searchform = forum_search_form($course, $search);
e6ae4dc8 160
a6855934 161$PAGE->navbar->add($strsearch, new moodle_url('/mod/forum/search.php', array('id'=>$course->id)));
b74c9a9f 162$PAGE->navbar->add($strsearchresults);
cd4e6b17 163if (!$posts = forum_search_posts($searchterms, $course->id, $page*$perpage, $perpage, $totalcount)) {
164 $PAGE->set_title($strsearchresults);
39790bd8 165 $PAGE->set_heading($course->fullname);
cd4e6b17 166 echo $OUTPUT->header();
66e2b9f8
AD
167 echo $OUTPUT->heading($strforums, 2);
168 echo $OUTPUT->heading($strsearchresults, 3);
169 echo $OUTPUT->heading(get_string("noposts", "forum"), 4);
77ffdf4b 170
cd4e6b17 171 if (!$individualparams) {
172 $words = $search;
e6ae4dc8 173 }
65bcf17b 174
cd4e6b17 175 forum_print_big_search_form($course);
176
177 echo $OUTPUT->footer();
178 exit;
179}
180
667f63fe
AD
181//including this here to prevent it being included if there are no search results
182require_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
cd4e6b17 192$PAGE->set_title($strsearchresults);
b4c07395 193$PAGE->set_heading($course->fullname);
cd4e6b17 194$PAGE->set_button($searchform);
195echo $OUTPUT->header();
196echo '<div class="reportlink">';
d2ba493c
AH
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,
dd223096
P
210 'showform' => 1,
211 'starredonly' => $starredonly
d2ba493c
AH
212];
213$url = new moodle_url("/mod/forum/search.php", $params);
214foreach ($tags as $tag) {
215 $url .= "&tags[]=$tag";
216}
217echo html_writer::link($url, get_string('advancedsearch', 'forum').'...');
218
cd4e6b17 219echo '</div>';
220
66e2b9f8
AD
221echo $OUTPUT->heading($strforums, 2);
222echo $OUTPUT->heading("$strsearchresults: $totalcount", 3);
cd4e6b17 223
1d67258e 224$url = new moodle_url('search.php', array('search' => $search, 'id' => $course->id, 'perpage' => $perpage));
929d7a83 225echo $OUTPUT->paging_bar($totalcount, $page, $perpage, $url);
cd4e6b17 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
233foreach ($searchterms as $key => $searchterm) {
234 if (preg_match('/^\-/',$searchterm)) {
235 unset($searchterms[$key]);
236 } else {
237 $searchterms[$key] = preg_replace('/^\+/','',$searchterm);
e6ae4dc8 238 }
cd4e6b17 239}
240$strippedsearch = implode(' ', $searchterms); // Rebuild the string
aa99838d
RW
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 = [];
501cdbd8 275
cd4e6b17 276foreach ($posts as $post) {
e6ae4dc8 277
cd4e6b17 278 // Replace the simple subject with the three items forum name -> thread name -> subject
279 // (if all three are appropriate) each as a link.
aa99838d 280 if (!isset($discussionsbyid[$post->discussion])) {
cd4e6b17 281 print_error('invaliddiscussionid', 'forum');
282 }
501cdbd8 283
aa99838d
RW
284 $discussion = $discussionsbyid[$post->discussion];
285 if (!isset($forumsbyid[$discussion->get_forum_id()])) {
286 print_error('invalidforumid', 'forum');
cd4e6b17 287 }
501cdbd8 288
aa99838d
RW
289 $forum = $forumsbyid[$discussion->get_forum_id()];
290 $capabilitymanager = $managerfactory->get_capability_manager($forum);
291 $postentity = $entityfactory->get_post_from_stdclass($post);
5da8e7d5 292
aa99838d
RW
293 if (!$capabilitymanager->can_view_post($USER, $discussion, $postentity)) {
294 // Don't render posts that the user can't view.
295 continue;
cd4e6b17 296 }
b800ac5a 297
aa99838d
RW
298 if ($postentity->is_deleted()) {
299 // Don't render deleted posts.
300 continue;
34edbe57
JSM
301 }
302
aa99838d 303 $poststorender[] = $postentity;
cd4e6b17 304}
501cdbd8 305
aa99838d
RW
306$renderer = $rendererfactory->get_posts_search_results_renderer($searchterms);
307echo $renderer->render(
308 $USER,
309 $forumsbyid,
310 $discussionsbyid,
311 $poststorender
312);
313
929d7a83 314echo $OUTPUT->paging_bar($totalcount, $page, $perpage, $url);
e6ae4dc8 315
cd4e6b17 316echo $OUTPUT->footer();
501cdbd8 317
e6ae4dc8 318
3a4ff0a8
AN
319 /**
320 * Print a full-sized search form for the specified course.
321 *
d9b196d9 322 * @param stdClass $course The Course that will be searched.
3a4ff0a8
AN
323 * @return void The function prints the form.
324 */
e6ae4dc8 325function forum_print_big_search_form($course) {
dd223096
P
326 global $PAGE, $words, $subject, $phrase, $user, $fullwords, $notwords, $datefrom,
327 $dateto, $forumid, $tags, $starredonly;
10deddd3
FM
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);
1da58a1a 338 $renderable->set_forumid($forumid);
d2ba493c 339 $renderable->set_tags($tags);
dd223096 340 $renderable->set_starredonly($starredonly);
10deddd3
FM
341
342 $output = $PAGE->get_renderer('mod_forum');
343 echo $output->render($renderable);
e6ae4dc8 344}
345
e9ff8e10 346/**
65bcf17b 347 * This function takes each word out of the search string, makes sure they are at least
3a4ff0a8
AN
348 * two characters long and returns an string of the space-separated search
349 * terms.
65bcf17b 350 *
3a4ff0a8
AN
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.
e9ff8e10 355 */
e6ae4dc8 356function 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
3a4ff0a8
AN
368 /**
369 * Retrieve a list of the forums that this user can view.
370 *
d9b196d9 371 * @param stdClass $course The Course to use.
3a4ff0a8
AN
372 * @return array A set of formatted forum names stored against the forum id.
373 */
77ffdf4b 374function forum_menu_list($course) {
77ffdf4b 375 $menu = array();
77ffdf4b 376
debd3d62 377 $modinfo = get_fast_modinfo($course);
debd3d62 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 }
bf0f06b1 386 $context = context_module::instance($cm->id);
debd3d62 387 if (!has_capability('mod/forum:viewdiscussion', $context)) {
388 continue;
77ffdf4b 389 }
debd3d62 390 $menu[$cm->instance] = format_string($cm->name);
77ffdf4b 391 }
392
393 return $menu;
394}