Xataface 2.0
Xataface Application Framework
Dataface/Index.php
Go to the documentation of this file.
00001 <?php
00046 class Dataface_Index {
00047 
00051         function createIndexTable(){
00052                 $sql = "create table dataface__index (
00053                         index_id int(11) not null auto_increment,
00054                         `table` varchar(64) not null,
00055                         record_id varchar(255) not null,
00056                         record_url varchar(255) not null,
00057                         record_title varchar(255) not null,
00058                         record_description text,
00059                         `lang` varchar(2) not null,
00060                         `searchable_text` text,
00061                         fulltext index `searchable_text_index` (`searchable_text`),
00062                         unique key `record_key` (`record_id`,`lang`),
00063                         primary key (`index_id`))";
00064                 $res = mysql_query($sql, df_db());
00065                 
00066                 if ( !$res ){
00067                         trigger_error(mysql_error(df_db()), E_USER_ERROR);
00068                 }
00069         }
00070         
00071         
00079         function indexRecord(&$record, $lang='*'){
00080                 $app =& Dataface_Application::getInstance();
00081                 if ( $lang == '*' ){
00082                         // If the language specified is '*', that means we will
00083                         // be indexing all languages.
00084                         $this->indexRecord($record, $app->_conf['lang']);
00085                         
00086                         if ( is_array($app->_conf['languages']) ){
00087                                 import('Dataface/IO.php');
00088                                 $io = new Dataface_IO($record->_table->tablename);
00089                                 foreach ( array_keys($app->_conf['languages']) as $lang){
00090                                         if ( $lang == $app->_conf['lang'] ){
00091                                                 continue;
00092                                         }
00093                                         $io->lang = $lang;
00094                                         $io->read($record->getId(), $record);
00095                                         $this->indexRecord($record, $lang);
00096                                 }
00097                         }
00098                         return true;
00099                 }
00100                 
00101                 if ( !isset($lang) ) $lang = $app->_conf['lang'];
00102                 
00103                 $del =& $record->_table->getDelegate();
00104                 if ( isset($del) and method_exists($del, 'getSearchableText') ){
00105                         $searchable_text = $del->getSearchableText($record);
00106                         if ( !is_string($searchable_text) ){
00107                                 // If this method returns anything other than a string, 
00108                                 // then we do not index the record... we just return false.
00109                                 return false;
00110                         }
00111                 } else {
00112                         // The getSearchableText() method is not defined, so we will
00113                         // just produce a concatenation of all text fields in the 
00114                         // record and index those.
00115                         $fields = $record->_table->getCharFields(true);
00116                         $searchable_text = implode(', ', $record->strvals($fields));
00117                 }
00118         
00119                 $sql = "
00120                         replace into dataface__index 
00121                         (`record_id`,`table`,`record_url`,`record_title`,`record_description`,`lang`,`searchable_text`)
00122                         values
00123                         (
00124                         '".addslashes($record->getId())."',
00125                         '".addslashes($record->_table->tablename)."',
00126                         '".addslashes($record->getPublicLink())."',
00127                         '".addslashes($record->getTitle())."',
00128                         '".addslashes(strip_tags($record->getDescription()))."',
00129                         '".addslashes($lang)."',
00130                         '".addslashes($searchable_text)."'
00131                         )";
00132                 if ( !@mysql_query($sql, df_db()) ){
00133                         $this->createIndexTable();
00134                         if ( !mysql_query($sql, df_db()) ){
00135                                 trigger_error(mysql_error(df_db()), E_USER_ERROR);
00136                         }
00137                 }
00138                 
00139                 
00140                 return true;
00141         }
00142         
00143         function indexFoundRecords($query, $lang='*'){
00144                 for ( $start = 0; $start >= 0; $start +=100 ){
00145                         // We do it in chunks of 100
00146                         
00147                         $records = df_get_records_array($query['-table'], $query, $start, 100, false);
00148                         if ( !$records or (count($records) == 0) or PEAR::isError($records) ) return true;
00149                         
00150                         foreach ($records as $record){
00151                                 
00152                                 $this->indexRecord($record, $lang);
00153                         }
00154                         unset($records);
00155                 }
00156         }
00157         
00158         function buildIndex($tables=null, $lang='*', $clear=true){
00159                 if ( $clear ){
00160                         $sql = "delete from dataface__index";
00161                         if ( !mysql_query($sql, df_db()) ){
00162                                 $this->createIndexTable();
00163                         }
00164                 }
00165                 foreach ( $tables as $tablename ){
00166                         if ( $this->isTableIndexable($tablename) ){
00167                                 $this->indexFoundRecords(array('-table'=>$tablename), $lang);
00168                         }
00169                 }
00170                 $sql = "optimize table dataface__index";
00171                 if ( !mysql_query($sql, df_db()) ){
00172                         $this->createIndexTable();
00173                         $sql = "optimize table dataface__index";
00174                         mysql_query($sql, df_db());
00175                 }
00176                 
00177 
00178         }
00179         
00180         function isTableIndexable($tablename){
00181                 $app =& Dataface_Application::getInstance();
00182                 $indexableTables = @$app->_conf['_index'];
00183                 if ( !is_array($indexableTables) ){
00184                         $indexableTables = array();
00185                 }
00186                 
00187                 if ( @$indexableTables['__default__'] ){
00188                         $default = 1;
00189                 } else {
00190                         $default = 0;
00191                 }
00192                 
00193                 $table =& Dataface_Table::loadTable($tablename);
00194                 if ( $default ){
00195                         if ( isset($table->_atts['__index__']) and $table->_atts['__index__'] == 0){
00196                                 return false;
00197                         } else {
00198                                 return true;
00199                         }
00200                 } else {
00201                         if ( @$indexableTables[$tablename] or @$table->_atts['__index__'] ){
00202                                 return true;
00203                         } else {
00204                                 return false;
00205                         }
00206                 }
00207         }
00208         
00209         function _cmp_words_by_length($a,$b){
00210                 if ( strlen($a) < strlen($b) ) return 1;
00211                 else if ( strlen($b) < strlen($a) ) return -1;
00212                 else return 0;
00213         }
00214         
00220         function find($query, $returnMetadata=false, $lang=null){
00221                 if ( !$lang ) $lang = @Dataface_Application::getInstance()->_conf['lang'];
00222                 if ( !$lang ) $lang = 'en';
00223                 
00224                 $select = "select record_id,`table`,record_url,record_title,record_description, `searchable_text`, `lang`,match(searchable_text) against ('".addslashes($query['-search'])."') as `relevance`";
00225                 $sql = "
00226                         
00227                         from dataface__index
00228                         where `lang`='".addslashes($lang)."' and 
00229                         match(searchable_text)
00230                         against ('".addslashes($query['-search'])."')";
00231                         
00232                 
00233                 $countsql = "select count(record_id), `table` as num ".$sql." group by `table`";
00234                 
00235                 if ( isset($query['-table']) ){
00236                         $sql .= " and `table` = '".addslashes($query['-table'])."'";
00237                 }
00238                 
00239                 
00240                 
00241                 if ( !isset($query['-limit']) ){
00242                         $query['-limit'] = 30;
00243                 }
00244                 
00245                 
00246                 
00247                 if ( !isset($query['-skip']) ){
00248                         $query['-skip'] = 0; 
00249                 }
00250                 $skip = intval($query['-skip']);
00251                 $limit = intval($query['-limit']);
00252                 $sql .= " limit $skip, $limit";
00253                 $sql = $select.$sql;
00254                 
00255                 $res = @mysql_query($sql, df_db());
00256                 if ( !$res ){
00257                         $this->createIndexTable();
00258                         $res = mysql_query($sql, df_db());
00259                         if ( !$res ){
00260                                 trigger_error(mysql_error(df_db()), E_USER_ERROR);
00261                         }
00262                 }
00263                 
00264                 $out = array();
00265                 $phrases = array();
00266                 $words = explode(' ', str_replace('"', '', $query['-search']));
00267                 if ( preg_match_all('/"([^"]+)"/', $query['-search'], $matches, PREG_PATTERN_ORDER) ){
00268                         foreach ($matches[1] as $m){
00269                                 $phrases[] = $m;
00270                         }
00271                 }
00272                 $numWords = count($words);
00273                 if ( $numWords > 1 ){
00274                         $words2 = array(implode(' ', $words));
00275                         for ( $i=0; $i<$numWords; $i++){
00276                                 for ( $j=$i; $j<$numWords; $j++){
00277                                         
00278                                         $temp = $words;
00279                                         for ( $k=$i; $k<=$j; $k++ ){
00280                                                 unset($temp[$k]);
00281                                         }
00282                                         $words2[] = implode(' ', $temp);
00283                                 }
00284                         }
00285                         $words = $words2;
00286                 }
00287                 
00288                 usort($words, array($this, '_cmp_words_by_length'));
00289                 
00290                 while ( $row = mysql_fetch_assoc($res) ){
00291                         $st = strip_tags($row['searchable_text']);
00292                         $st = html_entity_decode($st, ENT_COMPAT, Dataface_Application::getInstance()->_conf['oe']);
00293                         
00294                         unset($row['searchable_text']);
00295                         
00296                         $summary = array();
00297                         foreach ($phrases as $p){
00298                                 if ( preg_match_all('/.{0,50}'.preg_quote($p, '/').'.{0,50}/', $st, $matches, PREG_PATTERN_ORDER) ){
00299                                         //print_r($matches);
00300                                         foreach ($matches[0] as $m){
00301                                                 $summary[] = $m;
00302                                                 if ( count($summary) > 5 ) break;
00303                                         }
00304                                         //print_r($summary);
00305                                 }
00306                         }
00307                         
00308                         if ( !$summary ){
00309                                 foreach ($words as $p){
00310                                         if ( !trim($p) ) continue;
00311                                         if ( preg_match_all('/.{0,50}'.preg_quote($p, '/').'.{0,50}/', $st, $matches, PREG_PATTERN_ORDER) ){
00312                                                 foreach ($matches[0] as $m){
00313                                                         $summary[] = $m;
00314                                                         if ( count($summary) > 5 ) break;
00315                                                 }
00316                                         }
00317                                 }
00318                         }
00319                         if ( $summary ){
00320                                 $row['record_description'] = '...' .implode(' ... ', $summary).' ...';
00321                         }
00322                         
00323                         $out[] = $row;
00324                         
00325                 }
00326                 @mysql_free_result($res);
00327                 if ( $returnMetadata ){
00328                         $app =& Dataface_Application::getInstance();
00329                         $res = @mysql_query($countsql, df_db());
00330                         if ( !$res ) trigger_error(mysql_error(df_db()), E_USER_ERROR);
00331                         $found = 0;
00332                         $total_found = 0;
00333                         $tables_matches = array();
00334 
00335                         while ($row = mysql_fetch_row($res) ){
00336                                 
00337                                 $label = @$app->_conf['table_labels'][$row[1]];
00338                                 if ( !$label ) $label = @$app->tables[$row[1]];
00339                                 if ( !$label ) $label = $row[1];
00340                                 $tables_matches[ $row[1] ] = array('found'=>$row[0], 'label'=>$label);
00341                                 $total_found += intval($row[0]);
00342                                 if ( !@$query['-table'] or $query['-table'] == $row[1]  )$found += intval($row[0]);
00343                         }
00344                         @mysql_free_result($res);
00345                 
00346                         $meta = array();
00347                         $meta['found'] = $found;
00348                         $meta['skip'] = $query['-skip'];
00349                         $meta['limit'] = $query['-limit'];
00350                         $meta['start'] = $query['-skip'];
00351                         $meta['end'] = min($meta['start']+$meta['limit'], $meta['found']);
00352                         $meta['tables'] = $tables_matches;
00353                         $meta['table'] = $query['-table'];
00354                         $meta['table_objects'] =& $table_objects;
00355                         $meta['total_found'] = $total_found;
00356                         return array('results'=>$out, 'metadata'=>@$meta);
00357                 } else {
00358                         
00359                         return $out;
00360                 }
00361                 
00362         }
00363 }
 All Data Structures Namespaces Files Functions Variables Enumerations