MDL-11719 increased size of idnumber in user table - needed for some enrolment plugin...
[moodle.git] / search / indexer.php
1 <?php
2 /**
3 * Global Search Engine for Moodle
4 *
5 * @package search
6 * @category core
7 * @subpackage search_engine
8 * @author Michael Champanis (mchampan) [cynnical@gmail.com], Valery Fremaux [valery.fremaux@club-internet.fr] > 1.8
9 * @date 2008/03/31
10 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
11 *
12 * The indexer logic -
13 *
14 * Look through each installed module's or block's search document class file (/search/documents)
15 * for necessary search functions, and if they're present add the content to the index.
16 * Repeat this for blocks.
17 *
18 * Because the iterator/retrieval functions are now stored in /search/documents/<mod>_document.php,
19 * /mod/mod/lib.php doesn't have to be modified - and thus the search module becomes quite
20 * self-sufficient. URL's are now stored in the index, stopping us from needing to require
21 * the class files to generate a results page.
22 *
23 * Along with the index data, each document's summary gets stored in the database
24 * and synchronised to the index (flat file) via the primary key ('id') which is mapped
25 * to the 'dbid' field in the index
26 * */
28 //this'll take some time, set up the environment
29 @set_time_limit(0);
30 @ob_implicit_flush(true);
31 @ob_end_flush();
33 /**
34 * includes and requires
35 */
36 require_once('../config.php');
37 require_once("$CFG->dirroot/search/lib.php");
39 /// only administrators can index the moodle installation, because access to all pages is required
41     require_login();
42     
43     if (empty($CFG->enableglobalsearch)) {
44         error(get_string('globalsearchdisabled', 'search'));
45     }
46     
47     if (!isadmin()) {
48         error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
49     } 
50     
51 /// confirmation flag to prevent accidental reindexing (indexersplash.php is the correct entry point)
53     $sure = strtolower(optional_param('areyousure', '', PARAM_ALPHA));
54     
55     if ($sure != 'yes') {
56         mtrace("<pre>Sorry, you need to confirm indexing via <a href='indexersplash.php'>indexersplash.php</a>"
57               .". (<a href='index.php'>Back to query page</a>).</pre>");
58     
59         exit(0);
60     }
61     
62     //php5 found, continue including php5-only files
63     //require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
64     require_once("$CFG->dirroot/search/indexlib.php");
65     
66     mtrace('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /></head><body>');
67     mtrace('<pre>Server Time: '.date('r',time())."\n");
68     
69     if (isset($CFG->search_indexer_busy) && $CFG->search_indexer_busy == '1') {
70         //means indexing was not finished previously
71         mtrace("Warning: Indexing was not successfully completed last time, restarting.\n");
72     }
73     
74 /// turn on busy flag
76     set_config('search_indexer_busy', '1');
77     
78     //paths
79     $index_path = SEARCH_INDEX_PATH;
80     $index_db_file = "{$CFG->dirroot}/search/db/$CFG->dbtype.sql";
81     $dbcontrol = new IndexDBControl();
82     
83 /// setup directory in data root
85     if (!file_exists($index_path)) {
86         mtrace("Data directory ($index_path) does not exist, attempting to create.");
87         if (!mkdir($index_path)) {
88             search_pexit("Error creating data directory at: $index_path. Please correct.");
89         } else {
90             mtrace("Directory successfully created.");
91         } 
92     } else {
93         mtrace("Using $index_path as data directory.");
94     } 
95     
96     $index = new Zend_Search_Lucene($index_path, true);
97     
98     /*
99     OBSOLETE REGENERATION - DB installs with search block by now
100     if (!$dbcontrol->checkDB()) {
101         search_pexit("Database error. Please check settings/files.");
102     }
103     */
105 /// New regeneration
107     mtrace('Deleting old index entries.');
108     delete_records(SEARCH_DATABASE_TABLE);
109     
110 /// begin timer
112     search_stopwatch();
113     mtrace("Starting activity modules\n");
114     
115     //the presence of the required search functions -
116     // * mod_iterator
117     // * mod_get_content_for_index
118     //are the sole basis for including a module in the index at the moment.
119     $searchables = array();
120     
121 /// collects modules
123     if ($mods = get_records('modules', '', '', '', 'id,name')) {
124         $searchables = array_merge($searchables, $mods);
125     }
126     mtrace(count($searchables).' modules found.');
127       
128     // collects blocks as indexable information may be found in blocks either
129     if ($blocks = get_records('block', '', '', '', 'id,name')) {
130         // prepend the "block_" prefix to discriminate document type plugins
131         foreach(array_keys($blocks) as $aBlockId){
132             $blocks[$aBlockId]->name = 'block_'.$blocks[$aBlockId]->name;
133         }
134         $searchables = array_merge($searchables, $blocks);
135         mtrace(count($blocks).' blocks found.');
136     }
137       
138 /// add virtual modules onto the back of the array
140     $searchables = array_merge($searchables, search_get_additional_modules());
141     if ($searchables){
142         foreach ($searchables as $mod) {
143             $class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
144          
145             if (file_exists($class_file)) {
146                 include_once($class_file);
147     
148                 //build function names
149                 $iter_function = $mod->name.'_iterator';
150                 $index_function = $mod->name.'_get_content_for_index';
151                 $counter = 0;
152                 if (function_exists($index_function) && function_exists($iter_function)) {
153                     mtrace("Processing module function $index_function ...");
154                     $sources = $iter_function();
155                     if ($sources){
156                         foreach ($sources as $i) {
157                             $documents = $index_function($i);
158                   
159                             //begin transaction
160                             if ($documents){
161                                 foreach($documents as $document) {
162                                     $counter++;
163                                     
164                                     //object to insert into db
165                                     $dbid = $dbcontrol->addDocument($document);
166                                     
167                                     //synchronise db with index
168                                     $document->addField(Zend_Search_Lucene_Field::Keyword('dbid', $dbid));
169                                     
170                                     //add document to index
171                                     $index->addDocument($document);
172                                     
173                                     //commit every x new documents, and print a status message
174                                     if (($counter % 2000) == 0) {
175                                         $index->commit();
176                                         mtrace(".. $counter");
177                                     } 
178                                 }
179                             }
180                             //end transaction
181                         }
182                     }
183             
184                     //commit left over documents, and finish up
185                     $index->commit();
186           
187                     mtrace("-- $counter documents indexed");
188                     mtrace("done.\n");
189                 }
190             }
191         }
192     }
193       
194 /// finished modules
196     mtrace('Finished activity modules');
197     search_stopwatch();
198         
199     mtrace(".<br/><a href='index.php'>Back to query page</a>.");
200     mtrace('</pre>');
201     
202 /// finished, turn busy flag off
204     set_config('search_indexer_busy', '0');
205     
206 /// mark the time we last updated
208     set_config('search_indexer_run_date', time());
209     
210 /// and the index size
212     set_config('search_index_size', (int)$index->count());
214 ?>