Option for additional search types added.
[moodle.git] / search / indexer.php
1 <?php
2   /* The indexer logic -
3    * Look through each installed module's search document class file (/search/documents)
4    * for necessary search functions, and if they're present add the content to the index.
5    * Repeat this for blocks.
6    *
7    * Because the iterator/retrieval functions are now stored in /search/documents/mod_document.php,
8    * /mod/mod/lib.php doesn't have to be modified - and thus the search module becomes quite
9    * self-sufficient. URL's are now stored in the index, stopping us from needing to require
10    * the class files to generate a results page.
11    *
12    * Along with the index data, each document's summary gets stored in the database
13    * and synchronised to the index (flat file) via the primary key ('id') which is mapped
14    * to the 'db_id' field in the index
15    * */
17   //this'll take some time, set up the environment
18   @set_time_limit(0);
19   @ob_implicit_flush(true);
20   @ob_end_flush();  
22   require_once('../config.php');
23   require_once("$CFG->dirroot/search/lib.php");  
25   //only administrators can index the moodle installation, because access to all pages is required   
26   require_login();
28   if (!isadmin()) {
29     error("You need to be an admin user to use this page.", "$CFG->wwwroot/login/index.php");
30   } //if
31   
32   //confirmation flag to prevent accidental reindexing (indexersplash.php is the correct entry point)
33   $sure = strtolower(optional_param('areyousure', '', PARAM_ALPHA));
34   
35   if ($sure != 'yes') {
36     mtrace("<pre>Sorry, you need to confirm indexing via <a href='indexersplash.php'>indexersplash.php</a>"
37           .". (<a href='index.php'>Back to query page</a>).</pre>");
38           
39     exit(0);
40   } //if  
41   
42   //check for php5 (lib.php)
43   if (!search_check_php5()) {
44     $phpversion = phpversion();
45     mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version $phpversion)");
46     exit(0);
47   } //if
48     
49   //php5 found, continue including php5-only files
50   require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
51     
52   mtrace('<pre>Server Time: '.date('r',time())."\n");
54   if ($CFG->search_indexer_busy == '1') {
55     //means indexing was not finished previously
56     mtrace("Warning: Indexing was not successfully completed last time, restarting.\n");
57   } //if
59   //turn on busy flag
60   set_config('search_indexer_busy', '1');
61   
62   //paths
63   $index_path = SEARCH_INDEX_PATH;
64   $index_db_file = "$CFG->dirroot/search/db/$CFG->dbtype.sql";  
65   
66   //setup directory in data root
67   if (!file_exists($index_path)) {
68     mtrace("Data directory ($index_path) does not exist, attempting to create.");
69     if (!mkdir($index_path)) {
70       search_pexit("Error creating data directory at: $index_path. Please correct.");
71     } else {
72       mtrace("Directory successfully created.");
73     } //else
74   } else {
75     mtrace("Using $index_path as data directory.");
76   } //else
77   
78   $index = new Zend_Search_Lucene($index_path, true);
79   
80   //create the database tables
81   $tables = $db->MetaTables();
82     
83   if (in_array($CFG->prefix.'search_documents', $tables)) {
84     //delete_records('search_documents');    
85     //temporary measure - db doesn't have update scripts and I realised that cvs 1.1 db
86     //is incompatible with cvs 1.2! Must fix ASAP.    
87     execute_sql('drop table '.$CFG->prefix.'search_documents', false);
88     
89     ob_start(); //turn output buffering on - to hide modify_database() output
90     modify_database($index_db_file, '', false);
91     ob_end_clean(); //chuck the buffer and resume normal operation
92   } else {        
93     ob_start(); //turn output buffering on - to hide modify_database() output
94     modify_database($index_db_file, '', false);
95     ob_end_clean(); //chuck the buffer and resume normal operation
96   } //else
98   //begin timer
99   search_stopwatch();
100   mtrace("Starting activity modules\n");
101   
102   //the presence of the required search functions -
103   // * mod_iterator
104   // * mod_get_content_for_index
105   //are the sole basis for including a module in the index at the moment.
106   
107   if ($mods = get_records_select('modules' /*'index this module?' where statement*/)) {        
108     $mods = array_merge($mods, search_get_additional_modules());
109     
110     foreach ($mods as $mod) {      
111       $class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';              
112       
113       if (file_exists($class_file)) {
114         include_once($class_file);
115         
116         $iter_function = $mod->name.'_iterator';
117         $index_function = $mod->name.'_get_content_for_index';
118                 
119         $counter = 0;
120         $doc = new stdClass;
121                 
122         if (function_exists($index_function) && function_exists($iter_function)) {
123           mtrace("Processing module function $index_function ...");
124                      
125           foreach ($iter_function() as $i) {
126             $documents = $index_function($i);
127             
128             //begin transaction
129             
130             foreach($documents as $document) {
131               $counter++;
132                             
133               //object to insert into db                            
134               $doc->doctype   = $document->doctype;
135               $doc->title     = search_escape_string($document->title);
136               $doc->url       = search_escape_string($document->url);              
137               $doc->update    = time();                            
138               $doc->courseid  = $document->course_id;              
139               $doc->groupid   = $document->group_id;              
140               
141               //insert summary into db
142               $id = insert_record('search_documents', $doc);
143               
144               //synchronise db with index
145               $document->addField(Zend_Search_Lucene_Field::Keyword('dbid', $id));
146               
147               //add document to index
148               $index->addDocument($document);                  
149                             
150               //commit every x new documents, and print a status message                            
151               if (($counter%2000) == 0) {
152                 $index->commit();
153                 mtrace(".. $counter");
154               } //if
155             } //foreach
157             //end transaction
158             
159           } //foreach
160                   
161           //commit left over documents, and finish up  
162           $index->commit();
163           
164           mtrace("-- $counter documents indexed");
165           mtrace("done.\n");          
166         } //if
167       } //if
168     } //foreach
169   } //if
170   
171   //finished modules
172   mtrace('Finished activity modules');
173   search_stopwatch();
174   
175   //now blocks...
176   //
177   
178   mtrace(".<br><a href='index.php'>Back to query page</a>.");
179   mtrace('</pre>');
180   
181   //finished, turn busy flag off
182   set_config("search_indexer_busy", "0");
183   
184   //mark the time we last updated
185   set_config("search_indexer_run_date", time());
187 ?>