[ PHPXref.com ] [ Generated: Sun Jul 20 20:48:27 2008 ] [ TYPO3 4.0 ]
[ Index ]     [ Variables ]     [ Functions ]     [ Classes ]     [ Constants ]     [ Statistics ]

title

Body

[close]

/typo3/sysext/cms/tslib/ -> class.tslib_search.php (source)

   1  <?php
   2  /***************************************************************
   3  *  Copyright notice
   4  *
   5  *  (c) 1999-2005 Kasper Skaarhoj (kasperYYYY@typo3.com)
   6  *  All rights reserved
   7  *
   8  *  This script is part of the TYPO3 project. The TYPO3 project is
   9  *  free software; you can redistribute it and/or modify
  10  *  it under the terms of the GNU General Public License as published by
  11  *  the Free Software Foundation; either version 2 of the License, or
  12  *  (at your option) any later version.
  13  *
  14  *  The GNU General Public License can be found at
  15  *  http://www.gnu.org/copyleft/gpl.html.
  16  *  A copy is found in the textfile GPL.txt and important notices to the license
  17  *  from the author is found in LICENSE.txt distributed with these scripts.
  18  *
  19  *
  20  *  This script is distributed in the hope that it will be useful,
  21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23  *  GNU General Public License for more details.
  24  *
  25  *  This copyright notice MUST APPEAR in all copies of the script!
  26  ***************************************************************/
  27  /**
  28   * Searching in database tables, typ. "pages" and "tt_content"
  29   * Used to generate search queries for TypoScript.
  30   * The class is included from "class.tslib_pagegen.php" based on whether there has been detected content in the GPvar "sword"
  31   *
  32   * $Id: class.tslib_search.php,v 1.11 2005/04/01 14:37:14 typo3 Exp $
  33   * Revised for TYPO3 3.6 June/2003 by Kasper Skaarhoj
  34   *
  35   * @author    Kasper Skaarhoj <kasperYYYY@typo3.com>
  36   * @author    Rene Fritz    <r.fritz@colorcube.de>
  37   */
  38  /**
  39   * [CLASS/FUNCTION INDEX of SCRIPT]
  40   *
  41   *
  42   *
  43   *   88: class tslib_search
  44   *  127:     function register_tables_and_columns($requestedCols,$allowedCols)
  45   *  168:     function explodeCols($in)
  46   *  193:     function register_and_explode_search_string($sword)
  47   *  226:     function split($origSword, $specchars='+-', $delchars='+.,-')
  48   *  269:     function quotemeta($str)
  49   *  285:     function build_search_query($endClause)
  50   *  371:     function build_search_query_for_searchwords()
  51   *  413:     function get_operator($operator)
  52   *  436:     function count_query()
  53   *  449:     function execute_query()
  54   *  462:     function get_searchwords()
  55   *  477:     function get_searchwordsArray()
  56   *
  57   * TOTAL FUNCTIONS: 12
  58   * (This index is automatically created/updated by the extension "extdeveval")
  59   *
  60   */
  61  
  62  
  63  
  64  
  65  
  66  
  67  
  68  
  69  
  70  
  71  
  72  
  73  
  74  
  75  
  76  
  77  
  78  
  79  
  80  /**
  81   * Search class used for the content object SEARCHRESULT
  82   *
  83   * @author    Kasper Skaarhoj <kasperYYYY@typo3.com>
  84   * @package TYPO3
  85   * @subpackage tslib
  86   * @see    tslib_cObj::SEARCHRESULT()
  87   */
  88  class tslib_search {
  89      var $tables = Array ();
  90  
  91      var $group_by = 'PRIMARY_KEY';                            // Alternatively 'PRIMARY_KEY'; sorting by primary key
  92      var $default_operator = 'AND';                            // Standard SQL-operator between words
  93      var $operator_translate_table_caseinsensitive = TRUE;
  94      var $operator_translate_table = Array (                    // case-sensitiv. Defineres the words, which will be operators between words
  95          Array ('+' , 'AND'),
  96          Array ('|' , 'AND'),
  97          Array ('-' , 'AND NOT'),
  98              // english
  99          Array ('and' , 'AND'),
 100          Array ('or' , 'OR'),
 101          Array ('not' , 'AND NOT'),
 102      );
 103  
 104      // Internal
 105      var $sword_array;        // Contains the search-words and operators
 106      var $queryParts;        // Contains the query parts after processing.
 107  
 108      var $other_where_clauses;    // Addition to the whereclause. This could be used to limit search to a certain page or alike in the system.
 109      var $fTable;        // This is set with the foreign table that 'pages' are connected to.
 110  
 111      var $res_offset = 0;    // How many rows to offset from the beginning
 112      var $res_shows = 20;    // How many results to show (0 = no limit)
 113      var $res_count;            // Intern: How many results, there was last time (with the exact same searchstring.
 114  
 115      var $pageIdList='';        // List of pageIds.
 116  
 117      var $listOfSearchFields ='';
 118  
 119      /**
 120       * Creates the $this->tables-array.
 121       * The 'pages'-table is ALWAYS included as the search is page-based. Apart from this there may be one and only one table, joined with the pages-table. This table is the first table mentioned in the requested-list. If any more tables are set here, they are ignored.
 122       *
 123       * @param    string        is a list (-) of columns that we want to search. This could be input from the search-form (see TypoScript documentation)
 124       * @param    string        $allowedCols: is the list of columns, that MAY be searched. All allowed cols are set as result-fields. All requested cols MUST be in the allowed-fields list.
 125       * @return    void
 126       */
 127  	function register_tables_and_columns($requestedCols,$allowedCols)    {
 128          $rCols=$this->explodeCols($requestedCols);
 129          $aCols=$this->explodeCols($allowedCols);
 130  
 131          foreach ($rCols as $k => $v)    {
 132              $rCols[$k]=trim($v);
 133              if (in_array($rCols[$k], $aCols))    {
 134                  $parts = explode('.',$rCols[$k]);
 135                  $this->tables[$parts[0]]['searchfields'][] = $parts[1];
 136              }
 137          }
 138          $this->tables['pages']['primary_key'] = 'uid';
 139          $this->tables['pages']['resultfields'][] = 'uid';
 140          unset($this->tables['pages']['fkey']);
 141  
 142          foreach ($aCols as $k => $v)    {
 143              $aCols[$k]=trim($v);
 144              $parts = explode('.',$aCols[$k]);
 145              $this->tables[$parts[0]]['resultfields'][] = $parts[1].' AS '.str_replace('.','_',$aCols[$k]);
 146              $this->tables[$parts[0]]['fkey']='pid';
 147          }
 148  
 149          $this->fTable='';
 150          foreach ($this->tables as $t => $v)    {
 151              if ($t!='pages')    {
 152                  if (!$this->fTable)    {
 153                      $this->fTable = $t;
 154                  } else {
 155                      unset($this->tables[$t]);
 156                  }
 157              }
 158          }
 159      }
 160  
 161      /**
 162       * Function that can convert the syntax for entering which tables/fields the search should be conducted in.
 163       *
 164       * @param    string        This is the code-line defining the tables/fields to search. Syntax: '[table1].[field1]-[field2]-[field3] : [table2].[field1]-[field2]'
 165       * @return    array        An array where the values is "[table].[field]" strings to search
 166       * @see    register_tables_and_columns()
 167       */
 168  	function explodeCols($in)    {
 169          $theArray = explode(':',$in);
 170          $out = Array();
 171          while(list(,$val)=each($theArray))    {
 172              $val=trim($val);
 173              $parts = explode('.',$val);
 174              if ($parts[0] && $parts[1])    {
 175                  $subparts = explode('-',$parts[1]);
 176                  while(list(,$piece)=each($subparts))    {
 177                      $piece=trim($piece);
 178                      if ($piece)        $out[]=$parts[0].'.'.$piece;
 179                  }
 180              }
 181          }
 182          return $out;
 183      }
 184  
 185      /**
 186       * Takes a search-string (WITHOUT SLASHES or else it'll be a little sppooky , NOW REMEMBER to unslash!!)
 187       * Sets up $this->sword_array op with operators.
 188       * This function uses $this->operator_translate_table as well as $this->default_operator
 189       *
 190       * @param    string        The input search-word string.
 191       * @return    void
 192       */
 193  	function register_and_explode_search_string($sword)    {
 194          $sword = trim($sword);
 195          if ($sword)    {
 196              $components = $this->split($sword);
 197              $s_sword = '';     // the searchword is stored here during the loop
 198              if (is_array($components))    {
 199                  $i=0;
 200                  $lastoper = '';
 201                  reset($components);
 202                  while (list($key,$val) = each ($components))    {
 203                      $operator=$this->get_operator($val);
 204                      if ($operator)    {
 205                          $lastoper = $operator;
 206                      } elseif (strlen($val)>1) {        // A searchword MUST be at least two characters long!
 207                          $this->sword_array[$i]['sword'] = $val;
 208                          $this->sword_array[$i]['oper'] = ($lastoper) ? $lastoper : $this->default_operator;
 209                          $lastoper = '';
 210                          $i++;
 211                      }
 212                  }
 213              }
 214          }
 215      }
 216  
 217      /**
 218       * Used to split a search-word line up into elements to search for. This function will detect boolean words like AND and OR, + and -, and even find sentences encapsulated in ""
 219       * This function could be re-written to be more clean and effective - yet it's not that important.
 220       *
 221       * @param    string        The raw sword string from outside
 222       * @param    string        Special chars which are used as operators (+- is default)
 223       * @param    string        Special chars which are deleted if the append the searchword (+-., is default)
 224       * @return    mixed        Returns an ARRAY if there were search words, othervise the return value may be unset.
 225       */
 226  	function split($origSword, $specchars='+-', $delchars='+.,-')    {
 227          $sword = $origSword;
 228          $specs = '['.$this->quotemeta($specchars).']';
 229          $delchars = '['.$this->quotemeta($delchars).']';
 230  
 231              // As long as $sword is true (that means $sword MUST be reduced little by little until its empty inside the loop!)
 232          while ($sword)    {
 233              if (ereg('^"',$sword))    {        // There was a double-quote and we will then look for the ending quote.
 234                  $sword = ereg_replace('^"','',$sword);        // Removes first double-quote
 235                  ereg('^[^"]*',$sword,$reg);  // Removes everything till next double-quote
 236                  $value[] = $reg[0];  // reg[0] is the value, should not be trimmed
 237                  $sword = ereg_replace('^'.$this->quotemeta($reg[0]),'',$sword);
 238                  $sword = trim(ereg_replace('^"','',$sword));        // Removes last double-quote
 239              } elseif (ereg('^'.$specs,$sword,$reg)) {
 240                  $value[] = $reg[0];
 241                  $sword = trim(ereg_replace('^'.$specs,'',$sword));        // Removes = sign
 242              } elseif (ereg('[\+\-]',$sword)) {    // Check if $sword contains + or -
 243                      // + and - shall only be interpreted as $specchars when there's whitespace before it
 244                      // otherwise it's included in the searchword (e.g. "know-how")
 245                  $a_sword = explode(' ',$sword);    // explode $sword to single words
 246                  $word = array_shift($a_sword);    // get first word
 247                  $word = ereg_replace($delchars.'$','',$word);        // Delete $delchars at end of string
 248                  $value[] = $word;    // add searchword to values
 249                  $sword = implode(' ',$a_sword);    // re-build $sword
 250              } else {
 251                      // There are no double-quotes around the value. Looking for next (space) or special char.
 252                  ereg('^[^ '.$this->quotemeta($specchars).']*',$sword,$reg);
 253                  $word = ereg_replace($delchars.'$','',trim($reg[0]));        // Delete $delchars at end of string
 254                  $value[] = $word;
 255                  $sword = trim(ereg_replace('^'.$this->quotemeta($reg[0]),'',$sword));
 256              }
 257          }
 258  
 259          return $value;
 260      }
 261  
 262      /**
 263       * Local version of quotemeta. This is the same as the PHP function
 264       * but the vertical line, |, and minus, -, is also escaped with a slash.
 265       *
 266       * @param    string        String to pass through quotemeta()
 267       * @return    string        Return value
 268       */
 269  	function quotemeta($str)    {
 270          $str = str_replace('|','\|',quotemeta($str));
 271          #$str = str_replace('-','\-',$str);        // Breaks "-" which should NOT have a slash before it inside of [ ] in a regex.
 272          return $str;
 273      }
 274  
 275      /**
 276       * This creates the search-query.
 277       * In TypoScript this is used for searching only records not hidden, start/endtimed and fe_grouped! (enable-fields, see tt_content)
 278       * Sets $this->queryParts
 279       *
 280       * @param    string        $endClause is some extra conditions that the search must match.
 281       * @return    boolean        Returns true no matter what - sweet isn't it!
 282       * @access private
 283       * @see    tslib_cObj::SEARCHRESULT()
 284       */
 285  	function build_search_query($endClause) {
 286  
 287          if (is_array($this->tables))    {
 288              $tables = $this->tables;
 289              $primary_table = '';
 290  
 291                  // Primary key table is found.
 292              foreach($tables as $key => $val)    {
 293                  if ($tables[$key]['primary_key'])    {$primary_table = $key;}
 294              }
 295  
 296              if ($primary_table) {
 297  
 298                      // Initialize query parts:
 299                  $this->queryParts = array(
 300                      'SELECT' => '',
 301                      'FROM' => '',
 302                      'WHERE' => '',
 303                      'GROUPBY' => '',
 304                      'ORDERBY' => '',
 305                      'LIMIT' => '',
 306                  );
 307  
 308                      // Find tables / field names to select:
 309                  $fieldArray = array();
 310                  $tableArray = array();
 311                  foreach($tables as $key => $val)    {
 312                      $tableArray[] = $key;
 313                      $resultfields = $tables[$key]['resultfields'];
 314                      if (is_array($resultfields))    {
 315                          foreach($resultfields as $key2 => $val2)    {
 316                              $fieldArray[] = $key.'.'.$val2;
 317                          }
 318                      }
 319                  }
 320                  $this->queryParts['SELECT'] = implode(',',$fieldArray);
 321                  $this->queryParts['FROM'] = implode(',',$tableArray);
 322  
 323                      // Set join WHERE parts:
 324                  $whereArray = array();
 325  
 326                  $primary_table_and_key = $primary_table.'.'.$tables[$primary_table]['primary_key'];
 327                  $primKeys = Array();
 328                  foreach($tables as $key => $val)    {
 329                      $fkey = $tables[$key]['fkey'];
 330                      if ($fkey)    {
 331                           $primKeys[] = $key.'.'.$fkey.'='.$primary_table_and_key;
 332                      }
 333                  }
 334                  if (count($primKeys))    {
 335                      $whereArray[] = '('.implode(' OR ',$primKeys).')';
 336                  }
 337  
 338                      // Additional where clause:
 339                  if (trim($endClause))    {
 340                      $whereArray[] = trim($endClause);
 341                  }
 342  
 343                      // Add search word where clause:
 344                  $query_part = $this->build_search_query_for_searchwords();
 345                  if (!$query_part)    {
 346                      $query_part = '(0!=0)';
 347                  }
 348                  $whereArray[] = '('.$query_part.')';
 349  
 350                      // Implode where clauses:
 351                  $this->queryParts['WHERE'] = implode(' AND ',$whereArray);
 352  
 353                      // Group by settings:
 354                  if ($this->group_by)    {
 355                      if ($this->group_by == 'PRIMARY_KEY')    {
 356                          $this->queryParts['GROUPBY'] = $primary_table_and_key;
 357                      } else {
 358                          $this->queryParts['GROUPBY'] = $this->group_by;
 359                      }
 360                  }
 361              }
 362          }
 363      }
 364  
 365      /**
 366       * Creates the part of the SQL-sentence, that searches for the search-words ($this->sword_array)
 367       *
 368       * @return    string        Part of where class limiting result to the those having the search word.
 369       * @access private
 370       */
 371  	function build_search_query_for_searchwords()    {
 372  
 373          if (is_array($this->sword_array))    {
 374              $main_query_part = array();
 375  
 376              foreach($this->sword_array as $key => $val)    {
 377                  $s_sword = $this->sword_array[$key]['sword'];
 378  
 379                      // Get subQueryPart
 380                  $sub_query_part = array();
 381  
 382                  $this->listOfSearchFields='';
 383                  foreach($this->tables as $key3 => $val3)    {
 384                      $searchfields = $this->tables[$key3]['searchfields'];
 385                      if (is_array($searchfields))    {
 386                          foreach($searchfields as $key2 => $val2)    {
 387                              $this->listOfSearchFields.= $key3.'.'.$val2.',';
 388                              $sub_query_part[] = $key3.'.'.$val2.' LIKE \'%'.$GLOBALS['TYPO3_DB']->quoteStr($s_sword, $key3).'%\'';
 389                          }
 390                      }
 391                  }
 392  
 393                  if (count($sub_query_part))    {
 394                      $main_query_part[] = $this->sword_array[$key]['oper'];
 395                      $main_query_part[] = '('.implode(' OR ',$sub_query_part).')';
 396                  }
 397              }
 398  
 399              if (count($main_query_part))    {
 400                  unset($main_query_part[0]);    // Remove first part anyways.
 401                  return implode(' ',$main_query_part);
 402              }
 403          }
 404      }
 405  
 406      /**
 407       * This returns an SQL search-operator (eg. AND, OR, NOT) translated from the current localized set of operators (eg. in danish OG, ELLER, IKKE).
 408       *
 409       * @param    string        The possible operator to find in the internal operator array.
 410       * @return    string        If found, the SQL operator for the localized input operator.
 411       * @access private
 412       */
 413  	function get_operator($operator)    {
 414          $operator = trim($operator);
 415          $op_array = $this->operator_translate_table;
 416          reset ($op_array);
 417          if ($this->operator_translate_table_caseinsensitive)    {
 418              $operator = strtolower($operator);    // case-conversion is charset insensitive, but it doesn't spoil anything if input string AND operator table is already converted
 419          }
 420          while (list($key,$val) = each($op_array))    {
 421              $item = $op_array[$key][0];
 422              if ($this->operator_translate_table_caseinsensitive)    {
 423                  $item = strtolower($item);    // See note above.
 424              }
 425              if ($operator==$item)    {
 426                  return $op_array[$key][1];
 427              }
 428          }
 429      }
 430  
 431      /**
 432       * Counts the results and sets the result in $this->res_count
 433       *
 434       * @return    boolean        True, if $this->query was found
 435       */
 436  	function count_query() {
 437          if (is_array($this->queryParts))    {
 438              $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($this->queryParts['SELECT'], $this->queryParts['FROM'], $this->queryParts['WHERE'], $this->queryParts['GROUPBY']);
 439              $this->res_count = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
 440              return TRUE;
 441          }
 442      }
 443  
 444      /**
 445       * Executes the search, sets result pointer in $this->result
 446       *
 447       * @return    boolean        True, if $this->query was set and query performed
 448       */
 449  	function execute_query() {
 450          if (is_array($this->queryParts))    {
 451              $this->result = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($this->queryParts);
 452              return TRUE;
 453          }
 454      }
 455  
 456      /**
 457       * Returns URL-parameters with the current search words.
 458       * Used when linking to result pages so that search words can be highlighted.
 459       *
 460       * @return    string        URL-parameters with the searchwords
 461       */
 462  	function get_searchwords()    {
 463          $SWORD_PARAMS = '';
 464          if (is_array($this->sword_array))    {
 465              foreach($this->sword_array as $key => $val)    {
 466                  $SWORD_PARAMS.= '&sword_list[]='.rawurlencode($val['sword']);
 467              }
 468          }
 469          return $SWORD_PARAMS;
 470      }
 471  
 472      /**
 473       * Returns an array with the search words in
 474       *
 475       * @return    array        IF the internal sword_array contained search words it will return these, otherwise "void"
 476       */
 477  	function get_searchwordsArray()    {
 478          if (is_array($this->sword_array))    {
 479              foreach($this->sword_array as $key => $val)    {
 480                  $swords[] = $val['sword'];
 481              }
 482          }
 483          return $swords;
 484      }
 485  }
 486  
 487  
 488  
 489  
 490  if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['tslib/class.tslib_search.php'])    {
 491      include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['tslib/class.tslib_search.php']);
 492  }
 493  
 494  ?>


[ Powered by PHPXref - Served by Debian GNU/Linux ]