Documentation TYPO3 par Ameos |
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2004 Kasper Skaarhoj (kasperYYYY@typo3.com) 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00088 class tslib_search { 00089 var $tables = Array (); 00090 00091 var $group_by = 'PRIMARY_KEY'; // Alternatively 'PRIMARY_KEY'; sorting by primary key 00092 var $default_operator = 'AND'; // Standard SQL-operator between words 00093 var $operator_translate_table_caseinsensitive = '1'; 00094 var $operator_translate_table = Array ( // case-sensitiv. Defineres the words, which will be operators between words 00095 Array ('+' , 'AND'), 00096 Array ('-' , 'AND NOT'), 00097 // english 00098 Array ('AND' , 'AND'), 00099 Array ('OR' , 'OR'), 00100 Array ('NOT' , 'AND NOT'), 00101 // danish 00102 Array ('OG' , 'AND'), 00103 Array ('ELLER' , 'OR'), 00104 Array ('UDEN' , 'AND NOT') 00105 ); 00106 00107 // Internal 00108 var $sword_array; // Contains the search-words and operators 00109 var $queryParts; // Contains the query parts after processing. 00110 00111 var $other_where_clauses; // Addition to the whereclause. This could be used to limit search to a certain page or alike in the system. 00112 var $fTable; // This is set with the foreign table that 'pages' are connected to. 00113 00114 var $res_offset = 0; // How many rows to offset from the beginning 00115 var $res_shows = 20; // How many results to show (0 = no limit) 00116 var $res_count; // Intern: How many results, there was last time (with the exact same searchstring. 00117 00118 var $pageIdList=''; // List of pageIds. 00119 00120 var $listOfSearchFields =''; 00121 00130 function register_tables_and_columns($requestedCols,$allowedCols) { 00131 $rCols=$this->explodeCols($requestedCols); 00132 $aCols=$this->explodeCols($allowedCols); 00133 00134 foreach ($rCols as $k => $v) { 00135 $rCols[$k]=trim($v); 00136 if (in_array($rCols[$k], $aCols)) { 00137 $parts = explode('.',$rCols[$k]); 00138 $this->tables[$parts[0]]['searchfields'][] = $parts[1]; 00139 } 00140 } 00141 $this->tables['pages']['primary_key'] = 'uid'; 00142 $this->tables['pages']['resultfields'][] = 'uid'; 00143 unset($this->tables['pages']['fkey']); 00144 00145 foreach ($aCols as $k => $v) { 00146 $aCols[$k]=trim($v); 00147 $parts = explode('.',$aCols[$k]); 00148 $this->tables[$parts[0]]['resultfields'][] = $parts[1].' AS '.str_replace('.','_',$aCols[$k]); 00149 $this->tables[$parts[0]]['fkey']='pid'; 00150 } 00151 00152 $this->fTable=''; 00153 foreach ($this->tables as $t => $v) { 00154 if ($t!='pages') { 00155 if (!$this->fTable) { 00156 $this->fTable = $t; 00157 } else { 00158 unset($this->tables[$t]); 00159 } 00160 } 00161 } 00162 } 00163 00171 function explodeCols($in) { 00172 $theArray = explode(':',$in); 00173 $out = Array(); 00174 while(list(,$val)=each($theArray)) { 00175 $val=trim($val); 00176 $parts = explode('.',$val); 00177 if ($parts[0] && $parts[1]) { 00178 $subparts = explode('-',$parts[1]); 00179 while(list(,$piece)=each($subparts)) { 00180 $piece=trim($piece); 00181 if ($piece) $out[]=$parts[0].'.'.$piece; 00182 } 00183 } 00184 } 00185 return $out; 00186 } 00187 00196 function register_and_explode_search_string($sword) { 00197 $sword = trim($sword); 00198 if ($sword) { 00199 $components = $this->split($sword); 00200 $s_sword = ''; // the searchword is stored here during the loop 00201 if (is_array($components)) { 00202 $i=0; 00203 $lastoper = ''; 00204 reset($components); 00205 while (list($key,$val) = each ($components)) { 00206 $operator=$this->get_operator($val); 00207 if ($operator) { 00208 $lastoper = $operator; 00209 } elseif (strlen($val)>1) { // A searchword MUST be at least two characters long! 00210 $this->sword_array[$i]['sword'] = $val; 00211 $this->sword_array[$i]['oper'] = ($lastoper) ? $lastoper : $this->default_operator; 00212 $lastoper = ''; 00213 $i++; 00214 } 00215 } 00216 } 00217 } 00218 } 00219 00229 function split($origSword, $specchars='+-', $delchars='+.,-') { 00230 $sword = $origSword; 00231 $specs = '['.$this->quotemeta($specchars).']'; 00232 $delchars = '['.$this->quotemeta($delchars).']'; 00233 00234 // As long as $sword is true (that means $sword MUST be reduced little by little until its empty inside the loop!) 00235 while ($sword) { 00236 if (ereg('^"',$sword)) { // There was a double-quote and we will then look for the ending quote. 00237 $sword = ereg_replace('^"','',$sword); // Removes first double-quote 00238 ereg('^[^"]*',$sword,$reg); // Removes everything till next double-quote 00239 $value[] = $reg[0]; // reg[0] is the value, should not be trimmed 00240 $sword = ereg_replace('^'.$this->quotemeta($reg[0]),'',$sword); 00241 $sword = trim(ereg_replace('^"','',$sword)); // Removes last double-quote 00242 } elseif (ereg('^'.$specs,$sword,$reg)) { 00243 $value[] = $reg[0]; 00244 $sword = trim(ereg_replace('^'.$specs,'',$sword)); // Removes = sign 00245 } elseif (ereg('[\+\-]',$sword)) { // Check if $sword contains + or - 00246 // + and - shall only be interpreted as $specchars when there's whitespace before it 00247 // otherwise it's included in the searchword (e.g. "know-how") 00248 $a_sword = explode(' ',$sword); // explode $sword to single words 00249 $word = array_shift($a_sword); // get first word 00250 $word = ereg_replace($delchars.'$','',$word); // Delete $delchars at end of string 00251 $value[] = $word; // add searchword to values 00252 $sword = implode(' ',$a_sword); // re-build $sword 00253 } else { 00254 // There are no double-quotes around the value. Looking for next (space) or special char. 00255 ereg('^[^ '.$this->quotemeta($specchars).']*',$sword,$reg); 00256 $word = ereg_replace($delchars.'$','',trim($reg[0])); // Delete $delchars at end of string 00257 $value[] = $word; 00258 $sword = trim(ereg_replace('^'.$this->quotemeta($reg[0]),'',$sword)); 00259 } 00260 } 00261 00262 return $value; 00263 } 00264 00272 function quotemeta($str) { 00273 $str = str_replace('|','\|',quotemeta($str)); 00274 #$str = str_replace('-','\-',$str); // Breaks "-" which should NOT have a slash before it inside of [ ] in a regex. 00275 return $str; 00276 } 00277 00288 function build_search_query($endClause) { 00289 00290 if (is_array($this->tables)) { 00291 $tables = $this->tables; 00292 $primary_table = ''; 00293 00294 // Primary key table is found. 00295 foreach($tables as $key => $val) { 00296 if ($tables[$key]['primary_key']) {$primary_table = $key;} 00297 } 00298 00299 if ($primary_table) { 00300 00301 // Initialize query parts: 00302 $this->queryParts = array( 00303 'SELECT' => '', 00304 'FROM' => '', 00305 'WHERE' => '', 00306 'GROUPBY' => '', 00307 'ORDERBY' => '', 00308 'LIMIT' => '', 00309 ); 00310 00311 // Find tables / field names to select: 00312 $fieldArray = array(); 00313 $tableArray = array(); 00314 foreach($tables as $key => $val) { 00315 $tableArray[] = $key; 00316 $resultfields = $tables[$key]['resultfields']; 00317 if (is_array($resultfields)) { 00318 foreach($resultfields as $key2 => $val2) { 00319 $fieldArray[] = $key.'.'.$val2; 00320 } 00321 } 00322 } 00323 $this->queryParts['SELECT'] = implode(',',$fieldArray); 00324 $this->queryParts['FROM'] = implode(',',$tableArray); 00325 00326 // Set join WHERE parts: 00327 $whereArray = array(); 00328 00329 $primary_table_and_key = $primary_table.'.'.$tables[$primary_table]['primary_key']; 00330 $primKeys = Array(); 00331 foreach($tables as $key => $val) { 00332 $fkey = $tables[$key]['fkey']; 00333 if ($fkey) { 00334 $primKeys[] = $key.'.'.$fkey.'='.$primary_table_and_key; 00335 } 00336 } 00337 if (count($primKeys)) { 00338 $whereArray[] = '('.implode(' OR ',$primKeys).')'; 00339 } 00340 00341 // Additional where clause: 00342 if (trim($endClause)) { 00343 $whereArray[] = trim($endClause); 00344 } 00345 00346 // Add search word where clause: 00347 $query_part = $this->build_search_query_for_searchwords(); 00348 if (!$query_part) { 00349 $query_part = '(0!=0)'; 00350 } 00351 $whereArray[] = '('.$query_part.')'; 00352 00353 // Implode where clauses: 00354 $this->queryParts['WHERE'] = implode(' AND ',$whereArray); 00355 00356 // Group by settings: 00357 if ($this->group_by) { 00358 if ($this->group_by == 'PRIMARY_KEY') { 00359 $this->queryParts['GROUPBY'] = $primary_table_and_key; 00360 } else { 00361 $this->queryParts['GROUPBY'] = $this->group_by; 00362 } 00363 } 00364 } 00365 } 00366 } 00367 00374 function build_search_query_for_searchwords() { 00375 00376 if (is_array($this->sword_array)) { 00377 $main_query_part = array(); 00378 00379 foreach($this->sword_array as $key => $val) { 00380 $s_sword = $this->sword_array[$key]['sword']; 00381 00382 // Get subQueryPart 00383 $sub_query_part = array(); 00384 00385 $this->listOfSearchFields=''; 00386 foreach($this->tables as $key3 => $val3) { 00387 $searchfields = $this->tables[$key3]['searchfields']; 00388 if (is_array($searchfields)) { 00389 foreach($searchfields as $key2 => $val2) { 00390 $this->listOfSearchFields.= $key3.'.'.$val2.','; 00391 $sub_query_part[] = $key3.'.'.$val2.' LIKE "%'.$GLOBALS['TYPO3_DB']->quoteStr($s_sword, $key3).'%"'; 00392 } 00393 } 00394 } 00395 00396 if (count($sub_query_part)) { 00397 $main_query_part[] = $this->sword_array[$key]['oper']; 00398 $main_query_part[] = '('.implode(' OR ',$sub_query_part).')'; 00399 } 00400 } 00401 00402 if (count($main_query_part)) { 00403 unset($main_query_part[0]); // Remove first part anyways. 00404 return implode(' ',$main_query_part); 00405 } 00406 } 00407 } 00408 00416 function get_operator($operator) { 00417 $operator = trim($operator); 00418 $op_array = $this->operator_translate_table; 00419 reset ($op_array); 00420 if ($this->operator_translate_table_caseinsensitive) { 00421 $operator = strtoupper($operator); 00422 } 00423 while (list($key,$val) = each($op_array)) { 00424 $item = $op_array[$key][0]; 00425 if ($this->operator_translate_table_caseinsensitive) { 00426 $item = strtoupper($item); 00427 } 00428 if ($operator==$item) { 00429 return $op_array[$key][1]; 00430 } 00431 } 00432 } 00433 00439 function count_query() { 00440 if (is_array($this->queryParts)) { 00441 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($this->queryParts['SELECT'], $this->queryParts['FROM'], $this->queryParts['WHERE'], $this->queryParts['GROUPBY']); 00442 $this->res_count = $GLOBALS['TYPO3_DB']->sql_num_rows($res); 00443 return TRUE; 00444 } 00445 } 00446 00452 function execute_query() { 00453 if (is_array($this->queryParts)) { 00454 $this->result = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($this->queryParts); 00455 return TRUE; 00456 } 00457 } 00458 00465 function get_searchwords() { 00466 $SWORD_PARAMS=''; 00467 if (is_array($this->sword_array)) { 00468 foreach($this->sword_array as $key => $val) { 00469 $SWORD_PARAMS.='&sword_list[]='.rawurlencode($val['sword']); 00470 } 00471 } 00472 return $SWORD_PARAMS; 00473 } 00474 00480 function get_searchwordsArray() { 00481 if (is_array($this->sword_array)) { 00482 foreach($this->sword_array as $key => $val) { 00483 $swords[]=$val['sword']; 00484 } 00485 } 00486 return $swords; 00487 } 00488 } 00489 00490 00491 00492 00493 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['tslib/class.tslib_search.php']) { 00494 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['tslib/class.tslib_search.php']); 00495 } 00496 00497 ?>