Fixed couple bugs in query, and improved logic of querylib.
[moodle.git] / search / querylib.php
CommitLineData
d9e1bf24 1<?php
2 require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
3
4 class SearchResult {
5 public $url,
6 $title,
7 $doctype,
8 $author,
9 $score,
10 $number;
11 } //SearchResult
12
13
14 //split this into Cache class and extend to SearchCache?
15 class SearchCache {
16 private $mode,
17 $valid;
18
19 public function __construct($mode='session') {
20 $accepted_modes = array('session');
21
22 if (in_array($mode, $accepted_modes)) {
23 $this->mode = $mode;
24 } else {
25 $this->mode = 'session';
26 } //else
27
28 $this->valid = true;
29 } //constructor
30
31 public function can_cache() {
32 return $this->valid;
33 } //can_cache
34
35 public function cache($id=false, $object=false) {
36 //see if there was a previous query
37 $last_term = $this->fetch('search_last_term');
38
39 //if this query is different from the last, clear out the last one
40 if ($id != false and $last_term != $id) {
41 $this->clear($last_term);
42 } //if
43
44 //store the new query if id and object are passed in
45 if ($object and $id) {
46 $this->store('search_last_term', $id);
47 $this->store($id, $object);
48 return true;
49 //otherwise return the stored results
50 } else if ($id and $this->exists($id)) {
51 return $this->fetch($id);
52 } //else
53 } //cache
54
55 private function exists($id) {
56 switch ($this->mode) {
57 case 'session' :
58 return isset($_SESSION[$id]);
59 } //switch
60 } //exists
61
62 private function clear($id) {
63 switch ($this->mode) {
64 case 'session' :
65 unset($_SESSION[$id]);
66 session_unregister($id);
67 return;
68 } //switch
69 } //clear
70
71 private function fetch($id) {
72 switch ($this->mode) {
73 case 'session' :
74 return ($this->exists($id)) ? unserialize($_SESSION[$id]) : false;
75 } //switch
76 } //fetch
77
78 private function store($id, $object) {
79 switch ($this->mode) {
80 case 'session' :
81 $_SESSION[$id] = serialize($object);
82 return;
83 } //switch
84 } //store
85 } //SearchCache
86
87
88 class SearchQuery {
89 private $index,
90 $term,
91 $pagenumber,
92 $cache,
93 $validquery,
94 $validindex,
95 $results,
0d46c846 96 $results_per_page,
97 $total_results;
d9e1bf24 98
99 public function __construct($term='', $page=1, $results_per_page=10, $cache=false) {
100 global $CFG;
101
102 $this->term = $term;
103 $this->pagenumber = $page;
104 $this->cache = $cache;
105 $this->validquery = true;
106 $this->validindex = true;
107 $this->results_per_page = $results_per_page;
108
109 $index_path = SEARCH_INDEX_PATH;
110
111 try {
112 $this->index = new Zend_Search_Lucene($index_path, false);
113 } catch(Exception $e) {
114 $this->validindex = false;
115 return;
116 } //catch
117
118 if (empty($this->term)) {
119 $this->validquery = false;
120 } else {
121 $this->set_query($this->term);
122 } //else
123 } //constructor
124
125 public function set_query($term='') {
126 if (!empty($term)) {
127 $this->term = $term;
128 } //if
129
130 if (empty($this->term)) {
131 $this->validquery = false;
132 } else {
133 $this->validquery = true;
134 } //else
135
136 if ($this->validquery and $this->validindex) {
137 $this->results = $this->get_results();
138 } else {
139 $this->results = array();
140 } //else
141 } //set_query
142
143 public function results() {
0d46c846 144 return $this->results;
d9e1bf24 145 } //results
0d46c846 146
147 private function process_results($all=false) {
d9e1bf24 148 global $USER;
0d46c846 149
150 $term = strtolower($this->term);
d9e1bf24 151
0d46c846 152 //experimental - return more results
153 $strip_arr = array('author:', 'title:', '+', '-', 'doctype:');
154 $stripped_term = str_replace($strip_arr, '', $term);
d9e1bf24 155
0d46c846 156 $hits = $this->index->find($term." title:".$stripped_term." author:".$stripped_term);
157 //--
d9e1bf24 158
0d46c846 159 $hitcount = count($hits);
160 $this->total_results = $hitcount;
6f1b1da1 161
0d46c846 162 if ($hitcount == 0) return array();
163
164 $totalpages = ceil($hitcount/$this->results_per_page);
165
166 if (!$all) {
167 if ($hitcount < $this->results_per_page) {
168 $this->pagenumber = 1;
169 } else if ($this->pagenumber > $totalpages) {
170 $this->pagenumber =$totalpages;
171 } //if
172
173 $start = ($this->pagenumber - 1) * $this->results_per_page;
174 $end = $start + $this->results_per_page;
175
176 if ($end > $hitcount) {
177 $end = $hitcount;
178 } //if
179 } else {
180 $start = 0;
181 $end = $hitcount;
182 } //else
183
184 $resultdoc = new SearchResult();
185 $resultdocs = array();
186
187 for ($i = $start; $i < $end; $i++) {
188 $hit = $hits[$i];
189
d9e1bf24 190 //check permissions on each result
6e780562 191 if ($this->can_display($USER, $hit->id, $hit->doctype, $hit->course_id, $hit->group_id)) {
d9e1bf24 192 $resultdoc->number = $i;
193 $resultdoc->url = $hit->url;
194 $resultdoc->title = $hit->title;
195 $resultdoc->score = $hit->score;
196 $resultdoc->doctype = $hit->doctype;
197 $resultdoc->author = $hit->author;
198
199 //and store it
0d46c846 200 $resultdocs[] = clone($resultdoc);
d9e1bf24 201 } //if
202 } //foreach
0d46c846 203
d9e1bf24 204 return $resultdocs;
0d46c846 205 } //process_results
d9e1bf24 206
207 private function get_results() {
208 $cache = new SearchCache();
209
210 if ($this->cache and $cache->can_cache()) {
211 if (!($resultdocs = $cache->cache($this->term))) {
0d46c846 212 $resultdocs = $this->process_results();
d9e1bf24 213 //cache the results so we don't have to compute this on every page-load
214 $cache->cache($this->term, $resultdocs);
215 //print "Using new results.";
216 } else {
217 //There was something in the cache, so we're using that to save time
218 //print "Using cached results.";
219 } //else
220 } else {
221 //no caching :(
222 //print "Caching disabled!";
0d46c846 223 $resultdocs = $this->process_results();
d9e1bf24 224 } //else
225
226 return $resultdocs;
227 } //get_results
228
229 public function page_numbers() {
230 $pages = $this->total_pages();
6e780562 231 $query = htmlentities($this->term);
d9e1bf24 232 $page = $this->pagenumber;
233 $next = "Next";
234 $back = "Back";
235
236 $ret = "<div align='center' id='search_page_links'>";
237
238 //Back is disabled if we're on page 1
239 if ($page > 1) {
240 $ret .= "<a href='query.php?query_string=$query&page=".($page-1)."'>< $back</a>&nbsp;";
241 } else {
242 $ret .= "< $back&nbsp;";
243 } //else
244
245 //don't <a href> the current page
246 for ($i = 1; $i <= $pages; $i++) {
247 if ($page == $i) {
248 $ret .= "[$i]&nbsp;";
249 } else {
250 $ret .= "<a href='query.php?query_string=$query&page=$i'>$i</a>&nbsp;";
251 } //else
252 } //for
253
254 //Next disabled if we're on the last page
255 if ($page < $pages) {
256 $ret .= "<a href='query.php?query_string=$query&page=".($page+1)."'>$next ></a>&nbsp;";
257 } else {
258 $ret .= "$next >&nbsp;";
259 } //else
260
261 $ret .= "</div>";
262
263 //shorten really long page lists, to stop table distorting width-ways
264 if (strlen($ret) > 70) {
265 $start = 4;
266 $end = $page - 5;
267 $ret = preg_replace("/<a\D+\d+\D+>$start<\/a>.*?<a\D+\d+\D+>$end<\/a>/", '...', $ret);
268
269 $start = $page + 5;
270 $end = $pages - 3;
271 $ret = preg_replace("/<a\D+\d+\D+>$start<\/a>.*?<a\D+\d+\D+>$end<\/a>/", '...', $ret);
272 } //if
6e780562 273
d9e1bf24 274 return $ret;
275 } //page_numbers
276
277 //can the user see this result?
6e780562 278 private function can_display(&$user, $this_id, $doctype, $course_id, $group_id) {
d9e1bf24 279 //this function should return true/false depending on
280 //whether or not a user can see this resource
281 //..
282 //if one of you nice moodlers see this, feel free to
283 //implement it for me .. :-P
284 return true;
285 } //can_display
286
287 public function count() {
0d46c846 288 return $this->total_results;
d9e1bf24 289 } //count
290
d9e1bf24 291 public function is_valid() {
292 return ($this->validquery and $this->validindex);
293 } //is_valid
294
295 public function is_valid_query() {
296 return $this->validquery;
297 } //is_valid_query
298
299 public function is_valid_index() {
300 return $this->validindex;
301 } //is_valid_index
302
303 public function total_pages() {
304 return ceil($this->count()/$this->results_per_page);
305 } //pages
306
307 public function get_pagenumber() {
308 return $this->pagenumber;
309 } //get_pagenumber
310
311 public function get_results_per_page() {
312 return $this->results_per_page;
313 } //get_results_per_page
314 } //SearchQuery
315
316?>