global search MDL-25009 indexing failures in each module are now handled so that...
[moodle.git] / search / update.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     * @version prepared for 2.0
11     * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
12     *
13     * Index asynchronous updator
14     *
15     * Major chages in this review is passing the xxxx_db_names return to
16     * multiple arity to handle multiple document types modules
17     */
18     
19     /**
20     * includes and requires
21     */
22     require_once('../config.php');
24     if (!defined('MOODLE_INTERNAL')) {
25         die('Direct access to this script is forbidden.');    ///  It must be included from the cron script
26     }
28     global $DB;
30 /// makes inclusions of the Zend Engine more reliable                               
31     ini_set('include_path', $CFG->dirroot.DIRECTORY_SEPARATOR.'search'.PATH_SEPARATOR.ini_get('include_path'));
33     require_once($CFG->dirroot.'/search/lib.php');
34     require_once($CFG->dirroot.'/search/indexlib.php');
36 /// checks global search activation
38     // require_login();
39     
40     if (empty($CFG->enableglobalsearch)) {
41         print_error('globalsearchdisabled', 'search');
42     }
43     
44     /*
45     Obsolete with the MOODLE INTERNAL check
46     if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) {
47         print_error('beadmin', 'search', get_login_url());
48     }
49     */
51     try {
52         $index = new Zend_Search_Lucene(SEARCH_INDEX_PATH);
53     } catch(LuceneException $e) {
54         mtrace("Could not construct a valid index. Maybe the first indexation was never made, or files might be corrupted. Run complete indexation again.");
55         return;
56     }
57     $dbcontrol = new IndexDBControl();
58     $update_count = 0;
59     $mainstartupdatedate = time();
61 /// indexing changed resources
62     
63     mtrace("Starting index update (updates)...\n");
64     
65     if ($mods = search_collect_searchables(false, true)){
66         
67         foreach ($mods as $mod) {
68             $indexdate = 0;
69             $indexdatestring = 'search_indexer_update_date_'.$mod->name;
70             $startupdatedate = time();
71             if (isset($CFG->$indexdatestring)) {
72                 $indexdate = $CFG->$indexdatestring;
73             }
75             $class_file = $CFG->dirroot.'/search/documents/'.$mod->name.'_document.php';
76             $get_document_function = $mod->name.'_single_document';
77             $delete_function = $mod->name.'_delete';
78             $db_names_function = $mod->name.'_db_names';
79             $updates = array();
80             
81             if (file_exists($class_file)) {
82                 require_once($class_file);
83                 
84                 //if both required functions exist
85                 if (function_exists($delete_function) and function_exists($db_names_function) and function_exists($get_document_function)) {
86                     mtrace("Checking $mod->name module for updates.");
87                     $valuesArray = $db_names_function();
88                     if ($valuesArray){
89                         foreach($valuesArray as $values){
90                             $where = (isset($values[5]) and $values[5]!='') ? 'AND ('.$values[5].')' : '';
91                             $itemtypes = ($values[4] != '*' && $values[4] != 'any') ? " AND itemtype = '{$values[4]}' " : '' ;
92     
93                             //TODO: check 'in' syntax with other RDBMS' (add and update.php as well)
94                             $table = SEARCH_DATABASE_TABLE;
95                             $query = "
96                                 SELECT 
97                                     docid,
98                                     itemtype
99                                 FROM 
100                                     {{$table}}
101                                 WHERE
102                                     doctype = ?
103                                     $itemtypes
104                             ";
105                             $docIds = $DB->get_records_sql_menu($query, array($mod->name));
106                             if (!empty($docIds)){
107                                 list($usql, $params) = $DB->get_in_or_equal(array_keys($docIds));
108                                 $query = "
109                                     SELECT 
110                                         id, 
111                                         $values[0] as docid
112                                     FROM 
113                                         {{$values[1]}}
114                                     WHERE 
115                                         $values[3] > $indexdate AND 
116                                         id $usql
117                                     $where
118                                 ";
119                                 $records = $DB->get_records_sql($query, $params);
120                             } else {
121                                 $records = array();
122                             }
124                             foreach($records as $record) {
125                                 $updates[] = $delete_function($record->docid, $docIds[$record->docid]);
126                             } 
127                         }
129                         foreach ($updates as $update) {
130                             ++$update_count;
131                             $added_doc = false;
133                             //get old document for deletion later
134                             // change from default text only search to include numerals for this search.
135                             Zend_Search_Lucene_Analysis_Analyzer::setDefault(new Zend_Search_Lucene_Analysis_Analyzer_Common_TextNum_CaseInsensitive());
136                             $doc = $index->find("+docid:{$update->id} +doctype:{$mod->name} +itemtype:{$update->itemtype}");
137                             
138                             try {
139                                 //add new modified document back into index
140                                 $add = $get_document_function($update->id, $update->itemtype);
142                                 //object to insert into db
143                                 $dbid = $dbcontrol->addDocument($add);
145                                 //synchronise db with index
146                                 $add->addField(Zend_Search_Lucene_Field::Keyword('dbid', $dbid));
147                                 mtrace("  Add: $add->title (database id = $add->dbid, moodle instance id = $add->docid)");
148                                 $index->addDocument($add);
149                                 $added_doc = true;
150                             }
152                             catch (dml_write_exception $e) {
153                                 mtrace(" Add: FAILED adding '$add->title' ,  moodle instance id = $add->docid , Error: $e->error ");
154                                 mtrace($e);
155                                 $added_doc = false;
156                             }
158                             if ($added_doc) {
159                                 // ok we've successfully added the new document so far
160                                 // delete single previous old document
161                                 try {
162                                     //get the record, should only be one
163                                     foreach ($doc as $thisdoc) {
164                                         mtrace("  Delete: $thisdoc->title (database id = $thisdoc->dbid, index id = $thisdoc->id, moodle instance id = $thisdoc->docid)");
165                                         $dbcontrol->delDocument($thisdoc);
166                                         $index->delete($thisdoc->id);
167                                     }
168                                 }
170                                 catch (dml_write_exception $e) {
171                                     mtrace(" Delete: FAILED deleting '$thisdoc->title' ,  moodle instance id = $thisdoc->docid , Error: $e->error ");
172                                     mtrace($e);
173                                 }
174                             }
175                         } 
176                     }
177                     else{
178                         mtrace("No types to update.\n");
179                     }
180                     //commit changes
181                     $index->commit();
183                     //update index date
184                     set_config($indexdatestring, $startupdatedate);
186                     mtrace("Finished $mod->name.\n");
187                 } 
188             } 
189         } 
190     } 
191     
192     //commit changes
193     $index->commit();
195     //update index date
196     set_config('search_indexer_update_date', $mainstartupdatedate);
198     mtrace("Finished $update_count updates");
200 ?>