|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2009-2011 Michael Klapper <michael.klapper@aoemedia.de> 00006 * (c) 2010-2011 Jeff Segars <jeff@webempoweredchurch.org> 00007 * All rights reserved 00008 * 00009 * This script is part of the TYPO3 project. The TYPO3 project is 00010 * free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * The GNU General Public License can be found at 00016 * http://www.gnu.org/copyleft/gpl.html. 00017 * A copy is found in the textfile GPL.txt and important notices to the license 00018 * from the author is found in LICENSE.txt distributed with these scripts. 00019 * 00020 * 00021 * This script is distributed in the hope that it will be useful, 00022 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00024 * GNU General Public License for more details. 00025 * 00026 * This copyright notice MUST APPEAR in all copies of the script! 00027 ***************************************************************/ 00028 00029 /** 00030 * Class for handling backend live search. 00031 * 00032 * @author Michael Klapper <michael.klapper@aoemedia.de> 00033 * @author Jeff Segars <jeff@webempoweredchurch.org> 00034 * @package TYPO3 00035 * @subpackage t3lib 00036 */ 00037 class t3lib_search_livesearch { 00038 00039 /** 00040 * @var string 00041 */ 00042 const PAGE_JUMP_TABLE = 'pages'; 00043 00044 /** 00045 * @var integer 00046 */ 00047 const RECURSIVE_PAGE_LEVEL = 99; 00048 00049 /** 00050 * @var integer 00051 */ 00052 const GROUP_TITLE_MAX_LENGTH = 15; 00053 00054 /** 00055 * @var integer 00056 */ 00057 const RECORD_TITLE_MAX_LENGTH = 28; 00058 00059 /** 00060 * @var string 00061 */ 00062 private $queryString = ''; 00063 00064 /** 00065 * @var integer 00066 */ 00067 private $startCount = 0; 00068 00069 /** 00070 * @var integer 00071 */ 00072 private $limitCount = 5; 00073 00074 /** 00075 * @var string 00076 */ 00077 protected $userPermissions = ''; 00078 00079 /** 00080 * @var t3lib_search_livesearch_queryParser 00081 */ 00082 protected $queryParser = NULL; 00083 00084 /** 00085 * Initialize access settings. 00086 * 00087 * @return void 00088 */ 00089 public function __construct() { 00090 $this->userPermissions = $GLOBALS['BE_USER']->getPagePermsClause(1); 00091 $this->queryParser = t3lib_div::makeInstance('t3lib_search_livesearch_queryParser'); 00092 } 00093 00094 /** 00095 * Find records from database based on the given $searchQuery. 00096 * 00097 * @param string $searchQuery 00098 * @return string Edit link to an page record if exists. Otherwise an empty string will returned 00099 */ 00100 public function findPage($searchQuery) { 00101 $link = ''; 00102 $pageId = $this->queryParser->getId($searchQuery); 00103 $pageRecord = $this->findPageById($pageId); 00104 00105 if (!empty($pageRecord)) { 00106 $link = $this->getEditLink(self::PAGE_JUMP_TABLE, $this->findPageById($pageId)); 00107 } 00108 00109 return $link; 00110 } 00111 00112 /** 00113 * Find records from database based on the given $searchQuery. 00114 * 00115 * @param string $searchQuery 00116 * @return array Result list of database search. 00117 */ 00118 public function find($searchQuery) { 00119 $recordArray = array(); 00120 $pageIdList = $this->getAvailablePageIds( 00121 implode(',', $GLOBALS['BE_USER']->returnWebmounts()), 00122 self::RECURSIVE_PAGE_LEVEL 00123 ); 00124 $limit = $this->startCount . ',' . $this->limitCount; 00125 00126 if ($this->queryParser->isValidCommand($searchQuery)) { 00127 $this->setQueryString($this->queryParser->getSearchQueryValue($searchQuery)); 00128 $tableName = $this->queryParser->getTableNameFromCommand($searchQuery); 00129 if ($tableName) { 00130 $recordArray[] = $this->findByTable($tableName, $pageIdList, $limit); 00131 } 00132 } else { 00133 $this->setQueryString($searchQuery); 00134 $recordArray = $this->findByGlobalTableList($pageIdList); 00135 } 00136 00137 return $recordArray; 00138 } 00139 00140 /** 00141 * Retrieve the page record from given $id. 00142 * 00143 * @param integer $id 00144 * @return array 00145 */ 00146 protected function findPageById($id) { 00147 $pageRecord = array(); 00148 $row = t3lib_BEfunc::getRecord(self::PAGE_JUMP_TABLE, $id); 00149 00150 if (is_array($row)) { 00151 $pageRecord = $row; 00152 } 00153 00154 return $pageRecord; 00155 } 00156 00157 /** 00158 * Find records from all registered TCA table & column values. 00159 * 00160 * @param string $pageIdList Comma seperated list of page IDs 00161 * @return array Records found in the database matching the searchQuery 00162 */ 00163 protected function findByGlobalTableList($pageIdList) { 00164 $limit = $this->limitCount; 00165 $getRecordArray = array(); 00166 foreach ($GLOBALS['TCA'] as $tableName => $value) { 00167 $recordArray = $this->findByTable($tableName, $pageIdList, '0,' . $limit); 00168 $recordCount = count($recordArray); 00169 if ($recordCount) { 00170 $limit = $limit - $recordCount; 00171 $getRecordArray[] = $recordArray; 00172 00173 if ($limit <= 0) { 00174 break; 00175 } 00176 } 00177 } 00178 00179 return $getRecordArray; 00180 } 00181 00182 /** 00183 * Find records by given table name. 00184 * 00185 * @param string $tableName Database table name 00186 * @param string $pageIdList Comma seperated list of page IDs 00187 * @param string $limit MySql Limit notation 00188 * @return array Records found in the database matching the searchQuery 00189 * 00190 * @see getRecordArray() 00191 * @see makeOrderByTable() 00192 * @see makeQuerySearchByTable() 00193 * @see extractSearchableFieldsFromTable() 00194 */ 00195 protected function findByTable($tableName, $pageIdList, $limit) { 00196 $fieldsToSearchWithin = $this->extractSearchableFieldsFromTable($tableName); 00197 00198 $getRecordArray = array(); 00199 if (count($fieldsToSearchWithin) > 0) { 00200 $pageBasedPermission = ($tableName == 'pages' && $this->userPermissions) ? $this->userPermissions : '1=1 '; 00201 $where = 'pid IN (' . $pageIdList . ') AND ' . $pageBasedPermission . $this->makeQuerySearchByTable($tableName, $fieldsToSearchWithin); 00202 $orderBy = $this->makeOrderByTable($tableName); 00203 $getRecordArray = $this->getRecordArray( 00204 $tableName, 00205 $where, 00206 $this->makeOrderByTable($tableName), 00207 $limit 00208 ); 00209 } 00210 00211 return $getRecordArray; 00212 } 00213 00214 /** 00215 * Process the Database operation to get the search result. 00216 * 00217 * @param string $tableName Database table name 00218 * @param string $where 00219 * @param string $orderBy 00220 * @param string $limit MySql Limit notation 00221 * @return array 00222 * 00223 * @see t3lib_db::exec_SELECT_queryArray() 00224 * @see t3lib_db::sql_num_rows() 00225 * @see t3lib_db::sql_fetch_assoc() 00226 * @see t3lib_iconWorks::getSpriteIconForRecord() 00227 * @see getTitleFromCurrentRow() 00228 * @see getEditLink() 00229 */ 00230 protected function getRecordArray($tableName, $where, $orderBy, $limit) { 00231 $collect = array(); 00232 $isFirst = TRUE; 00233 $queryParts = array( 00234 'SELECT' => '*', 00235 'FROM' => $tableName, 00236 'WHERE' => $where, 00237 'ORDERBY' => $orderBy, 00238 'LIMIT' => $limit 00239 ); 00240 $result = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($queryParts); 00241 $dbCount = $GLOBALS['TYPO3_DB']->sql_num_rows($result); 00242 00243 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) { 00244 $collect[] = array( 00245 'id' => $tableName . ':' . $row['uid'], 00246 'recordTitle' => ($isFirst) ? $this->getRecordTitlePrep($this->getTitleOfCurrentRecordType($tableName), self::GROUP_TITLE_MAX_LENGTH) : '', 00247 'iconHTML' => t3lib_iconWorks::getSpriteIconForRecord($tableName, $row), 00248 'title' => $this->getRecordTitlePrep($this->getTitleFromCurrentRow($tableName, $row), self::RECORD_TITLE_MAX_LENGTH), 00249 'editLink' => $this->getEditLink($tableName, $row), 00250 ); 00251 $isFirst = FALSE; 00252 } 00253 00254 return $collect; 00255 } 00256 00257 /** 00258 * Build a backend edit link based on given record. 00259 * 00260 * @param string $tableName Record table name 00261 * @param array $row Current record row from database. 00262 * @return string Link to open an edit window for record. 00263 * 00264 * @see t3lib_BEfunc::readPageAccess() 00265 */ 00266 protected function getEditLink($tableName, $row) { 00267 $pageInfo = t3lib_BEfunc::readPageAccess($row['pid'], $this->userPermissions); 00268 $calcPerms = $GLOBALS['BE_USER']->calcPerms($pageInfo); 00269 $editLink = ''; 00270 00271 if ($tableName == 'pages') { 00272 $localCalcPerms = $GLOBALS['BE_USER']->calcPerms(t3lib_BEfunc::getRecord('pages', $row['uid'])); 00273 $permsEdit = $localCalcPerms & 2; 00274 } else { 00275 $permsEdit = $calcPerms & 16; 00276 } 00277 00278 // "Edit" link: ( Only if permissions to edit the page-record of the content of the parent page ($this->id) 00279 // @todo Is there an existing function to generate this link? 00280 if ($permsEdit) { 00281 $editLink = 'alt_doc.php?' . '&edit[' . $tableName . '][' . $row['uid'] . ']=edit'; 00282 } 00283 00284 return $editLink; 00285 } 00286 00287 /** 00288 * Retrieve the record name 00289 * 00290 * @param string $tableName Record table name 00291 * @return string 00292 */ 00293 protected function getTitleOfCurrentRecordType($tableName) { 00294 return $GLOBALS['LANG']->sL($GLOBALS['TCA'][$tableName]['ctrl']['title']); 00295 } 00296 00297 /** 00298 * Crops a title string to a limited lenght and if it really was cropped, wrap it in a <span title="...">|</span>, 00299 * which offers a tooltip with the original title when moving mouse over it. 00300 * 00301 * @param string $title: The title string to be cropped 00302 * @param integer $titleLength: Crop title after this length - if not set, BE_USER->uc['titleLen'] is used 00303 * @return string The processed title string, wrapped in <span title="...">|</span> if cropped 00304 */ 00305 public function getRecordTitlePrep($title, $titleLength = 0) { 00306 // If $titleLength is not a valid positive integer, use BE_USER->uc['titleLen']: 00307 if (!$titleLength || !t3lib_div::testInt($titleLength) || $titleLength < 0) { 00308 $titleLength = $GLOBALS['BE_USER']->uc['titleLen']; 00309 } 00310 00311 return htmlspecialchars(t3lib_div::fixed_lgd_cs($title, $titleLength)); 00312 ; 00313 } 00314 00315 /** 00316 * Retrieve the column name which contains the title value 00317 * 00318 * @param string $tableName Record table name 00319 * @param array $row Current record row from database. 00320 * @return string 00321 * 00322 * @todo Use the backend function to get the calculated label instead. 00323 */ 00324 protected function getTitleFromCurrentRow($tableName, $row) { 00325 $titleColumnName = $GLOBALS['TCA'][$tableName]['ctrl']['label']; 00326 return $row[$titleColumnName]; 00327 } 00328 00329 /** 00330 * Build the MySql where clause by table. 00331 * 00332 * @param string $tableName Record table name 00333 * @param array $fieldsToSearchWithin User right based visible fields where we can search within. 00334 * @return string 00335 */ 00336 protected function makeQuerySearchByTable($tableName, array $fieldsToSearchWithin) { 00337 // free text search 00338 $queryLikeStatement = ' LIKE \'%' . $this->getQueryString($tableName) . '%\''; 00339 $integerFieldsToSearchWithin = array(); 00340 $queryEqualStatement = ''; 00341 00342 if (is_numeric($this->getQueryString($tableName))) { 00343 $queryEqualStatement = ' = \'' . $this->getQueryString($tableName) . '\''; 00344 } 00345 $uidPos = array_search('uid', $fieldsToSearchWithin); 00346 if ($uidPos) { 00347 $integerFieldsToSearchWithin[] = 'uid'; 00348 unset($fieldsToSearchWithin[$uidPos]); 00349 } 00350 $pidPos = array_search('pid', $fieldsToSearchWithin); 00351 if ($pidPos) { 00352 $integerFieldsToSearchWithin[] = 'pid'; 00353 unset($fieldsToSearchWithin[$pidPos]); 00354 } 00355 00356 $queryPart = ' AND ('; 00357 if (count($integerFieldsToSearchWithin) && $queryEqualStatement !== '') { 00358 $queryPart .= implode($queryEqualStatement . ' OR ', $integerFieldsToSearchWithin) . $queryEqualStatement . ' OR '; 00359 } 00360 $queryPart .= implode($queryLikeStatement . ' OR ', $fieldsToSearchWithin) . $queryLikeStatement . ')'; 00361 $queryPart .= t3lib_BEfunc::deleteClause($tableName); 00362 $queryPart .= t3lib_BEfunc::versioningPlaceholderClause($tableName); 00363 00364 return $queryPart; 00365 } 00366 00367 /** 00368 * Build the MySql ORDER BY statement. 00369 * 00370 * 00371 * @param string $tableName Record table name 00372 * @return string 00373 * @see t3lib_db::stripOrderBy() 00374 */ 00375 protected function makeOrderByTable($tableName) { 00376 $orderBy = ''; 00377 00378 if (is_array($GLOBALS['TCA'][$tableName]['ctrl']) && array_key_exists('sortby', $GLOBALS['TCA'][$tableName]['ctrl'])) { 00379 $orderBy = 'ORDER BY ' . $GLOBALS['TCA'][$tableName]['ctrl']['sortby']; 00380 } else { 00381 $orderBy = $GLOBALS['TCA'][$tableName]['ctrl']['default_sortby']; 00382 } 00383 00384 return $GLOBALS['TYPO3_DB']->stripOrderBy($orderBy); 00385 } 00386 00387 /** 00388 * Get all fields from given table where we can search for. 00389 * 00390 * @param string $tableName 00391 * @return array 00392 */ 00393 protected function extractSearchableFieldsFromTable($tableName) { 00394 $fieldListArray = array(); 00395 00396 // Traverse configured columns and add them to field array, if available for user. 00397 foreach ((array) $GLOBALS['TCA'][$tableName]['columns'] as $fieldName => $fieldValue) { 00398 // @todo Reformat 00399 if ( 00400 (!$fieldValue['exclude'] || $GLOBALS['BE_USER']->check('non_exclude_fields', $tableName . ':' . $fieldName)) // does current user have access to the field 00401 && 00402 ($fieldValue['config']['type'] != 'passthrough') // field type is not searchable 00403 && 00404 (!preg_match('/date|time|int/', $fieldValue['config']['eval'])) // field can't be of type date, time, int 00405 && 00406 ( 00407 ($fieldValue['config']['type'] == 'text') 00408 || 00409 ($fieldValue['config']['type'] == 'input') 00410 ) 00411 ) { 00412 $fieldListArray[] = $fieldName; 00413 } 00414 } 00415 00416 // Add special fields: 00417 if ($GLOBALS['BE_USER']->isAdmin()) { 00418 $fieldListArray[] = 'uid'; 00419 $fieldListArray[] = 'pid'; 00420 } 00421 00422 return $fieldListArray; 00423 } 00424 00425 /** 00426 * Safely retrieve the queryString. 00427 * 00428 * @param string $tableName 00429 * @return string 00430 * @see t3lib_db::quoteStr() 00431 */ 00432 public function getQueryString($tableName = '') { 00433 return $GLOBALS['TYPO3_DB']->quoteStr($this->queryString, $tableName); 00434 } 00435 00436 /** 00437 * Setter for limit value. 00438 * 00439 * @param integer $limitCount 00440 * @return void 00441 */ 00442 public function setLimitCount($limitCount) { 00443 $limit = t3lib_div::intval_positive($limitCount); 00444 if ($limit > 0) { 00445 $this->limitCount = $limit; 00446 } 00447 } 00448 00449 /** 00450 * Setter for start count value. 00451 * 00452 * @param integer $startCount 00453 * @return void 00454 */ 00455 public function setStartCount($startCount) { 00456 $this->startCount = t3lib_div::intval_positive($startCount); 00457 } 00458 00459 /** 00460 * Setter for the search query string. 00461 * 00462 * @param string $queryString 00463 * @return void 00464 * @see t3lib_div::removeXSS() 00465 */ 00466 public function setQueryString($queryString) { 00467 $this->queryString = t3lib_div::removeXSS($queryString); 00468 } 00469 00470 /** 00471 * Creates an instance of t3lib_pageTree which will select a page tree to 00472 * $depth and return the object. In that object we will find the ids of the tree. 00473 * 00474 * @param integer Page id. 00475 * @param integer Depth to go down. 00476 * 00477 * @return string coma separated list of uids 00478 */ 00479 protected function getAvailablePageIds($id, $depth) { 00480 $idList = ''; 00481 $tree = t3lib_div::makeInstance('t3lib_pageTree'); 00482 $tree->init('AND ' . $this->userPermissions); 00483 $tree->makeHTML = 0; 00484 $tree->fieldArray = array('uid', 'php_tree_stop'); 00485 if ($depth) { 00486 $tree->getTree($id, $depth, ''); 00487 } 00488 $tree->ids[] = $id; 00489 $idList = implode(',', $tree->ids); 00490 return $idList; 00491 } 00492 } 00493 00494 ?>
1.8.0