3 * Global Search Engine for Moodle
7 * @subpackage search_engine
8 * @author Michael Champanis (mchampan) [cynnical@gmail.com], Valery Fremaux [valery.fremaux@club-internet.fr] > 1.8
10 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
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.
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.
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
28 //this'll take some time, set up the environment
30 @ob_implicit_flush
(true);
34 * includes and requires
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
43 if (empty($CFG->enableglobalsearch
)) {
44 error(get_string('globalsearchdisabled', 'search'));
48 error(get_string('beadmin', 'search'), "$CFG->wwwroot/login/index.php");
51 /// confirmation flag to prevent accidental reindexing (indexersplash.php is the correct entry point)
53 $sure = strtolower(optional_param('areyousure', '', PARAM_ALPHA
));
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>");
62 /// check for php5 (lib.php)
64 if (!search_check_php5()) {
65 $phpversion = phpversion();
66 mtrace("Sorry, global search requires PHP 5.0.0 or later (currently using version ".phpversion().")");
70 //php5 found, continue including php5-only files
71 //require_once("$CFG->dirroot/search/Zend/Search/Lucene.php");
72 require_once("$CFG->dirroot/search/indexlib.php");
74 mtrace('<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /></head><body>');
75 mtrace('<pre>Server Time: '.date('r',time())."\n");
77 if (isset($CFG->search_indexer_busy
) && $CFG->search_indexer_busy
== '1') {
78 //means indexing was not finished previously
79 mtrace("Warning: Indexing was not successfully completed last time, restarting.\n");
84 set_config('search_indexer_busy', '1');
87 $index_path = SEARCH_INDEX_PATH
;
88 $index_db_file = "{$CFG->dirroot}/search/db/$CFG->dbtype.sql";
89 $dbcontrol = new IndexDBControl();
91 /// setup directory in data root
93 if (!file_exists($index_path)) {
94 mtrace("Data directory ($index_path) does not exist, attempting to create.");
95 if (!mkdir($index_path)) {
96 search_pexit("Error creating data directory at: $index_path. Please correct.");
98 mtrace("Directory successfully created.");
101 mtrace("Using $index_path as data directory.");
104 $index = new Zend_Search_Lucene($index_path, true);
107 OBSOLETE REGENERATION - DB installs with search block by now
108 if (!$dbcontrol->checkDB()) {
109 search_pexit("Database error. Please check settings/files.");
115 mtrace('Deleting old index entries.');
116 delete_records(SEARCH_DATABASE_TABLE
);
121 mtrace("Starting activity modules\n");
123 //the presence of the required search functions -
125 // * mod_get_content_for_index
126 //are the sole basis for including a module in the index at the moment.
127 $searchables = array();
131 if ($mods = get_records('modules', '', '', '', 'id,name')) {
132 $searchables = array_merge($searchables, $mods);
134 mtrace(count($searchables).' modules found.');
136 // collects blocks as indexable information may be found in blocks either
137 if ($blocks = get_records('block', '', '', '', 'id,name')) {
138 // prepend the "block_" prefix to discriminate document type plugins
139 foreach(array_keys($blocks) as $aBlockId){
140 $blocks[$aBlockId]->name
= 'block_'.$blocks[$aBlockId]->name
;
142 $searchables = array_merge($searchables, $blocks);
143 mtrace(count($blocks).' blocks found.');
146 /// add virtual modules onto the back of the array
148 $searchables = array_merge($searchables, search_get_additional_modules());
150 foreach ($searchables as $mod) {
151 $class_file = $CFG->dirroot
.'/search/documents/'.$mod->name
.'_document.php';
153 if (file_exists($class_file)) {
154 include_once($class_file);
156 //build function names
157 $iter_function = $mod->name
.'_iterator';
158 $index_function = $mod->name
.'_get_content_for_index';
160 if (function_exists($index_function) && function_exists($iter_function)) {
161 mtrace("Processing module function $index_function ...");
162 $sources = $iter_function();
164 foreach ($sources as $i) {
165 $documents = $index_function($i);
169 foreach($documents as $document) {
172 //object to insert into db
173 $dbid = $dbcontrol->addDocument($document);
175 //synchronise db with index
176 $document->addField(Zend_Search_Lucene_Field
::Keyword('dbid', $dbid));
178 //add document to index
179 $index->addDocument($document);
181 //commit every x new documents, and print a status message
182 if (($counter %
2000) == 0) {
184 mtrace(".. $counter");
192 //commit left over documents, and finish up
195 mtrace("-- $counter documents indexed");
204 mtrace('Finished activity modules');
207 mtrace(".<br/><a href='index.php'>Back to query page</a>.");
210 /// finished, turn busy flag off
212 set_config('search_indexer_busy', '0');
214 /// mark the time we last updated
216 set_config('search_indexer_run_date', time());
218 /// and the index size
220 set_config('search_index_size', (int)$index->count());