2 require_once("{$CFG->dirroot}/search/Zend/Search/Lucene.php");
4 define('DEFAULT_POPUP_SETTINGS', "\"menubar=0,location=0,scrollbars,resizable,width=600,height=450\"");
7 * a class that represents a single result record of the search engine
19 //split this into Cache class and extend to SearchCache?
24 // foresees other caching locations
25 public function __construct($mode = 'session') {
26 $accepted_modes = array('session');
28 if (in_array($mode, $accepted_modes)) {
31 $this->mode
= 'session';
38 * returns the search cache status
41 public function can_cache() {
49 public function cache($id = false, $object = false) {
50 //see if there was a previous query
51 $last_term = $this->fetch('search_last_term');
53 //if this query is different from the last, clear out the last one
54 if ($id != false and $last_term != $id) {
55 $this->clear($last_term);
58 //store the new query if id and object are passed in
59 if ($object and $id) {
60 $this->store('search_last_term', $id);
61 $this->store($id, $object);
63 //otherwise return the stored results
65 else if ($id and $this->exists($id)) {
66 return $this->fetch($id);
71 * do key exist in cache ?
72 * @param id the object key
75 private function exists($id) {
76 switch ($this->mode
) {
78 return isset($_SESSION[$id]);
83 * clears a cached object in cache
84 * @param the object key to clear
87 private function clear($id) {
88 switch ($this->mode
) {
90 unset($_SESSION[$id]);
91 session_unregister($id);
97 * fetches a cached object
98 * @param id the object identifier
99 * @return the object cached
101 private function fetch($id) {
102 switch ($this->mode
) {
104 return ($this->exists($id)) ?
unserialize($_SESSION[$id]) : false;
109 * put an object in cache
110 * @param id the key for that object
111 * @param object the object to cache as a serialized value
114 private function store($id, $object) {
115 switch ($this->mode
) {
117 $_SESSION[$id] = serialize($object);
124 * Represents a single query with results
139 * constructor records query parameters
142 public function __construct($term = '', $page = 1, $results_per_page = 10, $cache = false) {
146 $this->pagenumber
= $page;
147 $this->cache
= $cache;
148 $this->validquery
= true;
149 $this->validindex
= true;
150 $this->results_per_page
= $results_per_page;
152 $index_path = SEARCH_INDEX_PATH
;
155 $this->index
= new Zend_Search_Lucene($index_path, false);
156 } catch(Exception
$e) {
157 $this->validindex
= false;
161 if (empty($this->term
)) {
162 $this->validquery
= false;
164 $this->set_query($this->term
);
169 * determines state of query object depending on query entry and
170 * tries to lauch search if all is OK
171 * @return void (this is only a state changing trigger).
173 public function set_query($term = '') {
178 if (empty($this->term
)) {
179 $this->validquery
= false;
182 $this->validquery
= true;
185 if ($this->validquery
and $this->validindex
) {
186 $this->results
= $this->get_results();
189 $this->results
= array();
194 * accessor to the result table.
195 * @return an array of result records
197 public function results() {
198 return $this->results
;
202 * do the effective collection of results
205 private function process_results($all=false) {
208 $term = strtolower($this->term
);
210 //experimental - return more results
211 $strip_arr = array('author:', 'title:', '+', '-', 'doctype:');
212 $stripped_term = str_replace($strip_arr, '', $term);
214 $hits = $this->index
->find($term." title:".$stripped_term." author:".$stripped_term);
217 $hitcount = count($hits);
218 $this->total_results
= $hitcount;
220 if ($hitcount == 0) return array();
222 $totalpages = ceil($hitcount/$this->results_per_page
);
225 if ($hitcount < $this->results_per_page
) {
226 $this->pagenumber
= 1;
228 else if ($this->pagenumber
> $totalpages) {
229 $this->pagenumber
= $totalpages;
232 $start = ($this->pagenumber
- 1) * $this->results_per_page
;
233 $end = $start +
$this->results_per_page
;
235 if ($end > $hitcount) {
244 $resultdoc = new SearchResult();
245 $resultdocs = array();
247 for ($i = $start; $i < $end; $i++
) {
250 //check permissions on each result
251 if ($this->can_display($USER, $hit->docid
, $hit->doctype
, $hit->course_id
, $hit->group_id
, $hit->path
, $hit->itemtype
, $hit->context_id
)) {
252 $resultdoc->number
= $i;
253 $resultdoc->url
= $hit->url
;
254 $resultdoc->title
= $hit->title
;
255 $resultdoc->score
= $hit->score
;
256 $resultdoc->doctype
= $hit->doctype
;
257 $resultdoc->author
= $hit->author
;
260 $resultdocs[] = clone($resultdoc);
263 // lowers total_results one unit
264 $this->total_results
--;
272 * get results of a search query using a caching strategy if available
273 * @return the result documents as an array of search objects
275 private function get_results() {
276 $cache = new SearchCache();
278 if ($this->cache
and $cache->can_cache()) {
279 if (!($resultdocs = $cache->cache($this->term
))) {
280 $resultdocs = $this->process_results();
281 //cache the results so we don't have to compute this on every page-load
282 $cache->cache($this->term
, $resultdocs);
283 //print "Using new results.";
286 //There was something in the cache, so we're using that to save time
287 //print "Using cached results.";
292 //print "Caching disabled!";
293 $resultdocs = $this->process_results();
300 * constructs the results paging links on results.
301 * @return string the results paging links
303 public function page_numbers() {
304 $pages = $this->total_pages();
305 $query = htmlentities($this->term
);
306 $page = $this->pagenumber
;
307 $next = get_string('next', 'search');
308 $back = get_string('back', 'search');
310 $ret = "<div align='center' id='search_page_links'>";
312 //Back is disabled if we're on page 1
314 $ret .= "<a href='query.php?query_string={$query}&page=".($page-1)."'>< {$back}</a> ";
316 $ret .= "< {$back} ";
319 //don't <a href> the current page
320 for ($i = 1; $i <= $pages; $i++
) {
322 $ret .= "($i) ";
324 $ret .= "<a href='query.php?query_string={$query}&page={$i}'>{$i}</a> ";
328 //Next disabled if we're on the last page
329 if ($page < $pages) {
330 $ret .= "<a href='query.php?query_string={$query}&page=".($page+
1)."'>{$next} ></a> ";
332 $ret .= "{$next} > ";
337 //shorten really long page lists, to stop table distorting width-ways
338 if (strlen($ret) > 70) {
341 $ret = preg_replace("/<a\D+\d+\D+>$start<\/a>.*?<a\D+\d+\D+>$end<\/a>/", '...', $ret);
345 $ret = preg_replace("/<a\D+\d+\D+>$start<\/a>.*?<a\D+\d+\D+>$end<\/a>/", '...', $ret);
352 * can the user see this result ?
353 * @param user a reference upon the user to be checked for access
354 * @param this_id the item identifier
355 * @param doctype the search document type. MAtches the module or block or
356 * extra search source definition
357 * @param course_id the course reference of the searched result
358 * @param group_id the group identity attached to the found resource
359 * @param path the path that routes to the local lib.php of the searched
360 * surrounding object fot that document
361 * @param item_type a subclassing information for complex module data models
362 * // TODO reorder parameters more consistently
364 private function can_display(&$user, $this_id, $doctype, $course_id, $group_id, $path, $item_type, $context_id) {
368 * course related checks
370 // admins can see everything, anyway.
375 // first check course compatibility against user : enrolled users to that course can see.
376 $myCourses = get_my_courses($user->id
);
377 $unenroled = !in_array($course_id, array_keys($myCourses));
379 // if guests are allowed, logged guest can see
380 $isallowedguest = (isguest()) ?
get_field('course', 'guest', 'id', $course_id) : false ;
382 if ($unenroled && !$isallowedguest){
386 // if user is enrolled or is allowed user and course is hidden, can he see it ?
387 $visibility = get_field('course', 'visible', 'id', $course_id);
388 if ($visibility <= 0){
389 if (!has_capability('moodle/course:viewhiddencourses', get_context_instance(CONTEXT_COURSE
, $course->id
))){
395 * prerecorded capabilities
397 // get context caching information and tries to discard unwanted records here
403 // then give back indexing data to the module for local check
404 include_once "{$CFG->dirroot}/search/documents/{$doctype}_document.php";
405 $access_check_function = "{$doctype}_check_text_access";
407 if (function_exists($access_check_function)){
408 $modulecheck = $access_check_function($path, $item_type, $this_id, $user, $group_id, $context_id);
409 // echo "module said $modulecheck for item $doctype/$item_type/$this_id";
410 return($modulecheck);
416 public function count() {
417 return $this->total_results
;
420 public function is_valid() {
421 return ($this->validquery
and $this->validindex
);
424 public function is_valid_query() {
425 return $this->validquery
;
428 public function is_valid_index() {
429 return $this->validindex
;
432 public function total_pages() {
433 return ceil($this->count()/$this->results_per_page
);
436 public function get_pagenumber() {
437 return $this->pagenumber
;
440 public function get_results_per_page() {
441 return $this->results_per_page
;
442 } //get_results_per_page