Modify a bunch of INSERTs to avoid using empty fields
[moodle.git] / search / querylib.php
1 <?php
2   require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
4   class SearchResult {
5     public  $url,
6             $title,            
7             $doctype,
8             $author,
9             $score,
10             $number;
11   } //SearchResult
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,
96             $results_per_page;
97     
98     public function __construct($term='', $page=1, $results_per_page=10, $cache=false) {
99       global $CFG;
100       
101       $this->term       = $term;
102       $this->pagenumber = $page;
103       $this->cache      = $cache;
104       $this->validquery = true;
105       $this->validindex = true;      
106       $this->results_per_page = $results_per_page;      
107       
108       $index_path = SEARCH_INDEX_PATH;
109       
110       try {
111         $this->index = new Zend_Search_Lucene($index_path, false);
112       } catch(Exception $e) {    
113         $this->validindex = false;        
114         return;
115       } //catch
116             
117       if (empty($this->term)) {
118         $this->validquery = false;
119       } else {
120         $this->set_query($this->term);
121       } //else      
122     } //constructor
123     
124     public function set_query($term='') {            
125       if (!empty($term)) {
126         $this->term = $term;
127       } //if
128       
129       if (empty($this->term)) {
130         $this->validquery = false;
131       } else {
132         $this->validquery = true;
133       } //else
134       
135       if ($this->validquery and $this->validindex) {
136         $this->results = $this->get_results();
137       } else {
138         $this->results = array();
139       } //else      
140     } //set_query
141     
142     public function results() {
143       if ($this->validquery and $this->validindex) {
144         return $this->get_subset_results();
145       } else {
146         return array();
147       } //else
148     } //results
149     
150     private function get_subset_results() {
151       if ($this->count() < $this->results_per_page) {
152         $this->pagenumber = 1;
153       } else if ($this->pagenumber > $this->total_pages()) {
154         $this->pagenumber = $this->total_pages();
155       } //if
156     
157       $start  = ($this->pagenumber - 1) * $this->results_per_page;
158                      
159       return array_slice($this->results, $start, $this->results_per_page);    
160     } //get_results
161     
162     private function get_all_results() {
163       global $USER;
164       
165       $resultdoc  = new SearchResult();
166       $resultdocs = array();
167       $i = 0;
168       
169       $term = strtolower($this->term);
170       
171       $hits = $this->index->find($term." title:".$term." author:".$term);
172             
173       foreach ($hits as $hit) {            
174         //check permissions on each result
175         if ($this->can_display($USER, $hit->id, $hit->doctype, $hit->course_id, $hit->group_id)) {
176           $resultdoc->number  = $i;
177           $resultdoc->url     = $hit->url;
178           $resultdoc->title   = $hit->title;
179           $resultdoc->score   = $hit->score;
180           $resultdoc->doctype = $hit->doctype;
181           $resultdoc->author  = $hit->author;
182         
183           //and store it
184           $resultdocs[] = clone($resultdoc);
185           
186           $i++;
187         } //if
188       } //foreach
189       
190       return $resultdocs;
191     } //get_all_results
192               
193     private function get_results() {
194       $cache = new SearchCache();
195       
196       if ($this->cache and $cache->can_cache()) {        
197         if (!($resultdocs = $cache->cache($this->term))) {
198           $resultdocs = $this->get_all_results();
199           //cache the results so we don't have to compute this on every page-load
200           $cache->cache($this->term, $resultdocs);          
201           //print "Using new results.";
202         } else {            
203           //There was something in the cache, so we're using that to save time
204           //print "Using cached results.";
205         } //else                
206       } else {
207         //no caching :(
208         //print "Caching disabled!";
209         $resultdocs = $this->get_all_results();
210       } //else
212       return $resultdocs;
213     } //get_results  
214     
215     public function page_numbers() {
216       $pages  = $this->total_pages();
217       $query  = htmlentities($this->term);     
218       $page   = $this->pagenumber;
219       $next   = "Next";
220       $back   = "Back";
221       
222       $ret = "<div align='center' id='search_page_links'>";    
223       
224       //Back is disabled if we're on page 1
225       if ($page > 1) {
226         $ret .= "<a href='query.php?query_string=$query&page=".($page-1)."'>< $back</a>&nbsp;";
227       } else {
228         $ret .= "< $back&nbsp;";
229       } //else
230       
231       //don't <a href> the current page
232       for ($i = 1; $i <= $pages; $i++) {
233         if ($page == $i) {
234           $ret .= "[$i]&nbsp;";
235         } else {
236           $ret .= "<a href='query.php?query_string=$query&page=$i'>$i</a>&nbsp;";
237         } //else
238       } //for
239       
240       //Next disabled if we're on the last page
241       if ($page < $pages) {      
242         $ret .= "<a href='query.php?query_string=$query&page=".($page+1)."'>$next ></a>&nbsp;";
243       } else {
244         $ret .= "$next >&nbsp;";
245       } //else
246       
247       $ret .= "</div>";    
248       
249       //shorten really long page lists, to stop table distorting width-ways
250       if (strlen($ret) > 70) {
251         $start = 4;
252         $end = $page - 5;     
253         $ret = preg_replace("/<a\D+\d+\D+>$start<\/a>.*?<a\D+\d+\D+>$end<\/a>/", '...', $ret);
254   
255         $start = $page + 5;
256         $end = $pages - 3;      
257         $ret = preg_replace("/<a\D+\d+\D+>$start<\/a>.*?<a\D+\d+\D+>$end<\/a>/", '...', $ret);
258       } //if
259      
260       return $ret;
261     } //page_numbers    
263     //can the user see this result?          
264     private function can_display(&$user, $this_id, $doctype, $course_id, $group_id) {
265       //this function should return true/false depending on
266       //whether or not a user can see this resource
267       //..
268       //if one of you nice moodlers see this, feel free to
269       //implement it for me .. :-P      
270       return true;
271     } //can_display
272     
273     public function count() {
274       return count($this->results);
275     } //count
276     
277     //this shouldn't be in this class
278     //public function index_count() {
279     //  return $this->index->count();
280     //} //index_count    
281     
282     public function is_valid() {
283       return ($this->validquery and $this->validindex);
284     } //is_valid
285     
286     public function is_valid_query() {
287       return $this->validquery;
288     } //is_valid_query
290     public function is_valid_index() {
291       return $this->validindex;
292     } //is_valid_index
293     
294     public function total_pages() {
295       return ceil($this->count()/$this->results_per_page);
296     } //pages    
297     
298     public function get_pagenumber() {
299       return $this->pagenumber;
300     } //get_pagenumber
301     
302     public function get_results_per_page() {
303       return $this->results_per_page;
304     } //get_results_per_page        
305   } //SearchQuery
307 ?>