Xataface  2.0alpha2
Xataface Application Framework
 All Data Structures Namespaces Files Functions Variables Groups Pages
Index.php
Go to the documentation of this file.
1 <?php
47 
51  function createIndexTable(){
52  $sql = "create table dataface__index (
53  index_id int(11) not null auto_increment,
54  `table` varchar(64) not null,
55  record_id varchar(255) not null,
56  record_url varchar(255) not null,
57  record_title varchar(255) not null,
58  record_description text,
59  `lang` varchar(2) not null,
60  `searchable_text` text,
61  fulltext index `searchable_text_index` (`searchable_text`),
62  unique key `record_key` (`record_id`,`lang`),
63  primary key (`index_id`))";
64  $res = mysql_query($sql, df_db());
65 
66  if ( !$res ){
67  trigger_error(mysql_error(df_db()), E_USER_ERROR);
68  }
69  }
70 
71 
79  function indexRecord(&$record, $lang='*'){
81  if ( $lang == '*' ){
82  // If the language specified is '*', that means we will
83  // be indexing all languages.
84  $this->indexRecord($record, $app->_conf['lang']);
85 
86  if ( is_array($app->_conf['languages']) ){
87  import('Dataface/IO.php');
88  $io = new Dataface_IO($record->_table->tablename);
89  foreach ( array_keys($app->_conf['languages']) as $lang){
90  if ( $lang == $app->_conf['lang'] ){
91  continue;
92  }
93  $io->lang = $lang;
94  $io->read($record->getId(), $record);
95  $this->indexRecord($record, $lang);
96  }
97  }
98  return true;
99  }
100 
101  if ( !isset($lang) ) $lang = $app->_conf['lang'];
102 
103  $del =& $record->_table->getDelegate();
104  if ( isset($del) and method_exists($del, 'getSearchableText') ){
105  $searchable_text = $del->getSearchableText($record);
106  if ( !is_string($searchable_text) ){
107  // If this method returns anything other than a string,
108  // then we do not index the record... we just return false.
109  return false;
110  }
111  } else {
112  // The getSearchableText() method is not defined, so we will
113  // just produce a concatenation of all text fields in the
114  // record and index those.
115  $fields = $record->_table->getCharFields(true);
116  $searchable_text = implode(', ', $record->strvals($fields));
117  }
118 
119  $sql = "
120  replace into dataface__index
121  (`record_id`,`table`,`record_url`,`record_title`,`record_description`,`lang`,`searchable_text`)
122  values
123  (
124  '".addslashes($record->getId())."',
125  '".addslashes($record->_table->tablename)."',
126  '".addslashes($record->getPublicLink())."',
127  '".addslashes($record->getTitle())."',
128  '".addslashes(strip_tags($record->getDescription()))."',
129  '".addslashes($lang)."',
130  '".addslashes($searchable_text)."'
131  )";
132  if ( !@mysql_query($sql, df_db()) ){
133  $this->createIndexTable();
134  if ( !mysql_query($sql, df_db()) ){
135  trigger_error(mysql_error(df_db()), E_USER_ERROR);
136  }
137  }
138 
139 
140  return true;
141  }
142 
143  function indexFoundRecords($query, $lang='*'){
144  for ( $start = 0; $start >= 0; $start +=100 ){
145  // We do it in chunks of 100
146 
147  $records = df_get_records_array($query['-table'], $query, $start, 100, false);
148  if ( !$records or (count($records) == 0) or PEAR::isError($records) ) return true;
149 
150  foreach ($records as $record){
151 
152  $this->indexRecord($record, $lang);
153  }
154  unset($records);
155  }
156  }
157 
158  function buildIndex($tables=null, $lang='*', $clear=true){
159  if ( $clear ){
160  $sql = "delete from dataface__index";
161  if ( !mysql_query($sql, df_db()) ){
162  $this->createIndexTable();
163  }
164  }
165  foreach ( $tables as $tablename ){
166  if ( $this->isTableIndexable($tablename) ){
167  $this->indexFoundRecords(array('-table'=>$tablename), $lang);
168  }
169  }
170  $sql = "optimize table dataface__index";
171  if ( !mysql_query($sql, df_db()) ){
172  $this->createIndexTable();
173  $sql = "optimize table dataface__index";
174  mysql_query($sql, df_db());
175  }
176 
177 
178  }
179 
182  $indexableTables = @$app->_conf['_index'];
183  if ( !is_array($indexableTables) ){
184  $indexableTables = array();
185  }
186 
187  if ( @$indexableTables['__default__'] ){
188  $default = 1;
189  } else {
190  $default = 0;
191  }
192 
194  if ( $default ){
195  if ( isset($table->_atts['__index__']) and $table->_atts['__index__'] == 0){
196  return false;
197  } else {
198  return true;
199  }
200  } else {
201  if ( @$indexableTables[$tablename] or @$table->_atts['__index__'] ){
202  return true;
203  } else {
204  return false;
205  }
206  }
207  }
208 
209  function _cmp_words_by_length($a,$b){
210  if ( strlen($a) < strlen($b) ) return 1;
211  else if ( strlen($b) < strlen($a) ) return -1;
212  else return 0;
213  }
214 
220  function find($query, $returnMetadata=false, $lang=null){
221  if ( !$lang ) $lang = @Dataface_Application::getInstance()->_conf['lang'];
222  if ( !$lang ) $lang = 'en';
223 
224  $select = "select record_id,`table`,record_url,record_title,record_description, `searchable_text`, `lang`,match(searchable_text) against ('".addslashes($query['-search'])."') as `relevance`";
225  $sql = "
226 
227  from dataface__index
228  where `lang`='".addslashes($lang)."' and
229  match(searchable_text)
230  against ('".addslashes($query['-search'])."')";
231 
232 
233  $countsql = "select count(record_id), `table` as num ".$sql." group by `table`";
234 
235  if ( isset($query['-table']) ){
236  $sql .= " and `table` = '".addslashes($query['-table'])."'";
237  }
238 
239 
240 
241  if ( !isset($query['-limit']) ){
242  $query['-limit'] = 30;
243  }
244 
245 
246 
247  if ( !isset($query['-skip']) ){
248  $query['-skip'] = 0;
249  }
250  $skip = intval($query['-skip']);
251  $limit = intval($query['-limit']);
252  $sql .= " limit $skip, $limit";
253  $sql = $select.$sql;
254 
255  $res = @mysql_query($sql, df_db());
256  if ( !$res ){
257  $this->createIndexTable();
258  $res = mysql_query($sql, df_db());
259  if ( !$res ){
260  trigger_error(mysql_error(df_db()), E_USER_ERROR);
261  }
262  }
263 
264  $out = array();
265  $phrases = array();
266  $words = explode(' ', str_replace('"', '', $query['-search']));
267  if ( preg_match_all('/"([^"]+)"/', $query['-search'], $matches, PREG_PATTERN_ORDER) ){
268  foreach ($matches[1] as $m){
269  $phrases[] = $m;
270  }
271  }
272  $numWords = count($words);
273  if ( $numWords > 1 ){
274  $words2 = array(implode(' ', $words));
275  for ( $i=0; $i<$numWords; $i++){
276  for ( $j=$i; $j<$numWords; $j++){
277 
278  $temp = $words;
279  for ( $k=$i; $k<=$j; $k++ ){
280  unset($temp[$k]);
281  }
282  $words2[] = implode(' ', $temp);
283  }
284  }
285  $words = $words2;
286  }
287 
288  usort($words, array($this, '_cmp_words_by_length'));
289 
290  while ( $row = mysql_fetch_assoc($res) ){
291  $st = strip_tags($row['searchable_text']);
292  $st = html_entity_decode($st, ENT_COMPAT, Dataface_Application::getInstance()->_conf['oe']);
293 
294  unset($row['searchable_text']);
295 
296  $summary = array();
297  foreach ($phrases as $p){
298  if ( preg_match_all('/.{0,50}'.preg_quote($p, '/').'.{0,50}/', $st, $matches, PREG_PATTERN_ORDER) ){
299  //print_r($matches);
300  foreach ($matches[0] as $m){
301  $summary[] = $m;
302  if ( count($summary) > 5 ) break;
303  }
304  //print_r($summary);
305  }
306  }
307 
308  if ( !$summary ){
309  foreach ($words as $p){
310  if ( !trim($p) ) continue;
311  if ( preg_match_all('/.{0,50}'.preg_quote($p, '/').'.{0,50}/', $st, $matches, PREG_PATTERN_ORDER) ){
312  foreach ($matches[0] as $m){
313  $summary[] = $m;
314  if ( count($summary) > 5 ) break;
315  }
316  }
317  }
318  }
319  if ( $summary ){
320  $row['record_description'] = '...' .implode(' ... ', $summary).' ...';
321  }
322 
323  $out[] = $row;
324 
325  }
326  @mysql_free_result($res);
327  if ( $returnMetadata ){
329  $res = @mysql_query($countsql, df_db());
330  if ( !$res ) trigger_error(mysql_error(df_db()), E_USER_ERROR);
331  $found = 0;
332  $total_found = 0;
333  $tables_matches = array();
334 
335  while ($row = mysql_fetch_row($res) ){
336 
337  $label = @$app->_conf['table_labels'][$row[1]];
338  if ( !$label ) $label = @$app->tables[$row[1]];
339  if ( !$label ) $label = $row[1];
340  $tables_matches[ $row[1] ] = array('found'=>$row[0], 'label'=>$label);
341  $total_found += intval($row[0]);
342  if ( !@$query['-table'] or $query['-table'] == $row[1] )$found += intval($row[0]);
343  }
344  @mysql_free_result($res);
345 
346  $meta = array();
347  $meta['found'] = $found;
348  $meta['skip'] = $query['-skip'];
349  $meta['limit'] = $query['-limit'];
350  $meta['start'] = $query['-skip'];
351  $meta['end'] = min($meta['start']+$meta['limit'], $meta['found']);
352  $meta['tables'] = $tables_matches;
353  $meta['table'] = $query['-table'];
354  $meta['table_objects'] =& $table_objects;
355  $meta['total_found'] = $total_found;
356  return array('results'=>$out, 'metadata'=>@$meta);
357  } else {
358 
359  return $out;
360  }
361 
362  }
363 }