[TASK] Use arrays in str_replace() calls
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / ContentObject / SearchResultContentObject.php
1 <?php
2 namespace TYPO3\CMS\Frontend\ContentObject;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2013 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Search class used for the content object SEARCHRESULT
31 * and searching in database tables, typ. "pages" and "tt_content"
32 * Used to generate search queries for TypoScript.
33 * The class is included from "class.tslib_pagegen.php" based on whether there has been detected content in the GPvar "sword"
34 */
35 class SearchResultContentObject extends \TYPO3\CMS\Frontend\ContentObject\AbstractContentObject {
36 /**
37 * @todo Define visibility
38 */
39 public $tables = array();
40
41 // Alternatively 'PRIMARY_KEY'; sorting by primary key
42 /**
43 * @todo Define visibility
44 */
45 public $group_by = 'PRIMARY_KEY';
46
47 // Standard SQL-operator between words
48 /**
49 * @todo Define visibility
50 */
51 public $default_operator = 'AND';
52
53 /**
54 * @todo Define visibility
55 */
56 public $operator_translate_table_caseinsensitive = TRUE;
57
58 // case-sensitiv. Defineres the words, which will be operators between words
59 /**
60 * @todo Define visibility
61 */
62 public $operator_translate_table = array(
63 array('+', 'AND'),
64 array('|', 'AND'),
65 array('-', 'AND NOT'),
66 // english
67 array('and', 'AND'),
68 array('or', 'OR'),
69 array('not', 'AND NOT')
70 );
71
72 // Internal
73 // Contains the search-words and operators
74 /**
75 * @todo Define visibility
76 */
77 public $sword_array;
78
79 // Contains the query parts after processing.
80 /**
81 * @todo Define visibility
82 */
83 public $queryParts;
84
85 // Addition to the whereclause. This could be used to limit search to a certain page or alike in the system.
86 /**
87 * @todo Define visibility
88 */
89 public $other_where_clauses;
90
91 // This is set with the foreign table that 'pages' are connected to.
92 /**
93 * @todo Define visibility
94 */
95 public $fTable;
96
97 // How many rows to offset from the beginning
98 /**
99 * @todo Define visibility
100 */
101 public $res_offset = 0;
102
103 // How many results to show (0 = no limit)
104 /**
105 * @todo Define visibility
106 */
107 public $res_shows = 20;
108
109 // Intern: How many results, there was last time (with the exact same searchstring.
110 /**
111 * @todo Define visibility
112 */
113 public $res_count;
114
115 // List of pageIds.
116 /**
117 * @todo Define visibility
118 */
119 public $pageIdList = '';
120
121 /**
122 * @todo Define visibility
123 */
124 public $listOfSearchFields = '';
125
126 /**
127 * Override default constructor to make it possible to instantiate this
128 * class for indexed_search
129 *
130 * @param \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $cObj
131 */
132 public function __construct(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $cObj = NULL) {
133 if (!is_null($cObj)) {
134 $this->cObj = $cObj;
135 $this->fileFactory = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance();
136 }
137 }
138
139 /**
140 * Rendering the cObject, SEARCHRESULT
141 *
142 * @param array $conf Array of TypoScript properties
143 * @return string Output
144 */
145 public function render($conf = array()) {
146 if (\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('sword') && \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('scols')) {
147 $this->register_and_explode_search_string(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('sword'));
148 $this->register_tables_and_columns(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('scols'), $conf['allowedCols']);
149 // Depth
150 $depth = 100;
151 // The startId is found
152 $theStartId = 0;
153 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('stype'))) {
154 $temp_theStartId = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('stype');
155 $rootLine = $GLOBALS['TSFE']->sys_page->getRootLine($temp_theStartId);
156 // The page MUST have a rootline with the Level0-page of the current site inside!!
157 foreach ($rootLine as $val) {
158 if ($val['uid'] == $GLOBALS['TSFE']->tmpl->rootLine[0]['uid']) {
159 $theStartId = $temp_theStartId;
160 }
161 }
162 } elseif (\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('stype')) {
163 if (substr(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('stype'), 0, 1) == 'L') {
164 $pointer = intval(substr(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('stype'), 1));
165 $theRootLine = $GLOBALS['TSFE']->tmpl->rootLine;
166 // location Data:
167 $locDat_arr = explode(':', \TYPO3\CMS\Core\Utility\GeneralUtility::_POST('locationData'));
168 $pId = intval($locDat_arr[0]);
169 if ($pId) {
170 $altRootLine = $GLOBALS['TSFE']->sys_page->getRootLine($pId);
171 ksort($altRootLine);
172 if (count($altRootLine)) {
173 // Check if the rootline has the real Level0 in it!!
174 $hitRoot = 0;
175 $theNewRoot = array();
176 foreach ($altRootLine as $val) {
177 if ($hitRoot || $val['uid'] == $GLOBALS['TSFE']->tmpl->rootLine[0]['uid']) {
178 $hitRoot = 1;
179 $theNewRoot[] = $val;
180 }
181 }
182 if ($hitRoot) {
183 // Override the real rootline if any thing
184 $theRootLine = $theNewRoot;
185 }
186 }
187 }
188 $key = $this->cObj->getKey($pointer, $theRootLine);
189 $theStartId = $theRootLine[$key]['uid'];
190 }
191 }
192 if (!$theStartId) {
193 // If not set, we use current page
194 $theStartId = $GLOBALS['TSFE']->id;
195 }
196 // Generate page-tree
197 $this->pageIdList .= $this->cObj->getTreeList(-1 * $theStartId, $depth);
198 $endClause = 'pages.uid IN (' . $this->pageIdList . ')
199 AND pages.doktype in (' . $GLOBALS['TYPO3_CONF_VARS']['FE']['content_doktypes'] . ($conf['addExtUrlsAndShortCuts'] ? ',3,4' : '') . ')
200 AND pages.no_search=0' . $this->cObj->enableFields($this->fTable) . $this->cObj->enableFields('pages');
201 if ($conf['languageField.'][$this->fTable]) {
202 // (using sys_language_uid which is the ACTUAL language of the page.
203 // sys_language_content is only for selecting DISPLAY content!)
204 $endClause .= ' AND ' . $this->fTable . '.' . $conf['languageField.'][$this->fTable] . ' = ' . intval($GLOBALS['TSFE']->sys_language_uid);
205 }
206 // Build query
207 $this->build_search_query($endClause);
208 // Count...
209 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('scount'))) {
210 $this->res_count = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('scount');
211 } else {
212 $this->count_query();
213 }
214 // Range
215 $spointer = intval(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('spointer'));
216 $range = isset($conf['range.']) ? $this->cObj->stdWrap($conf['range'], $conf['range.']) : $conf['range'];
217 if ($range) {
218 $theRange = intval($range);
219 } else {
220 $theRange = 20;
221 }
222 // Order By:
223 $noOrderBy = isset($conf['noOrderBy.']) ? $this->cObj->stdWrap($conf['noOrderBy'], $conf['noOrderBy.']) : $conf['noOrderBy'];
224 if (!$noOrderBy) {
225 $this->queryParts['ORDERBY'] = 'pages.lastUpdated, pages.tstamp';
226 }
227 $this->queryParts['LIMIT'] = $spointer . ',' . $theRange;
228 // Search...
229 $this->execute_query();
230 if ($GLOBALS['TYPO3_DB']->sql_num_rows($this->result)) {
231 $GLOBALS['TSFE']->register['SWORD_PARAMS'] = $this->get_searchwords();
232 $total = $this->res_count;
233 $rangeLow = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($spointer + 1, 1, $total);
234 $rangeHigh = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($spointer + $theRange, 1, $total);
235 // prev/next url:
236 $target = isset($conf['target.']) ? $this->cObj->stdWrap($conf['target'], $conf['target.']) : $conf['target'];
237 $LD = $GLOBALS['TSFE']->tmpl->linkData($GLOBALS['TSFE']->page, $target, 1, '', '', $this->cObj->getClosestMPvalueForPage($GLOBALS['TSFE']->page['uid']));
238 $targetPart = $LD['target'] ? ' target="' . htmlspecialchars($LD['target']) . '"' : '';
239 $urlParams = $this->cObj->URLqMark($LD['totalURL'], '&sword=' . rawurlencode(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('sword')) . '&scols=' . rawurlencode(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('scols')) . '&stype=' . rawurlencode(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('stype')) . '&scount=' . $total);
240 // substitution:
241 $result = str_replace(
242 array(
243 '###RANGELOW###',
244 '###RANGEHIGH###',
245 '###TOTAL###'
246 ),
247 array(
248 $rangeLow,
249 $rangeHigh,
250 $total
251 ),
252 $this->cObj->cObjGetSingle($conf['layout'], $conf['layout.'], 'layout')
253 );
254 if ($rangeHigh < $total) {
255 $next = $this->cObj->cObjGetSingle($conf['next'], $conf['next.'], 'next');
256 $next = '<a href="' . htmlspecialchars(($urlParams . '&spointer=' . ($spointer + $theRange))) . '"' . $targetPart . $GLOBALS['TSFE']->ATagParams . '>' . $next . '</a>';
257 } else {
258 $next = '';
259 }
260 $result = str_replace('###NEXT###', $next, $result);
261 if ($rangeLow > 1) {
262 $prev = $this->cObj->cObjGetSingle($conf['prev'], $conf['prev.'], 'prev');
263 $prev = '<a href="' . htmlspecialchars(($urlParams . '&spointer=' . ($spointer - $theRange))) . '"' . $targetPart . $GLOBALS['TSFE']->ATagParams . '>' . $prev . '</a>';
264 } else {
265 $prev = '';
266 }
267 $result = str_replace('###PREV###', $prev, $result);
268 // Searching result
269 $theValue = $this->cObj->cObjGetSingle($conf['resultObj'], $conf['resultObj.'], 'resultObj');
270 $cObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
271 $cObj->setParent($this->cObj->data, $this->cObj->currentRecord);
272 $renderCode = '';
273 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($this->result)) {
274 // versionOL() here? This is search result displays, is that possible to preview anyway?
275 // Or are records selected here already future versions?
276 $cObj->start($row);
277 $renderCode .= $cObj->cObjGetSingle($conf['renderObj'], $conf['renderObj.'], 'renderObj');
278 }
279 $renderWrap = isset($conf['renderWrap.']) ? $this->cObj->stdWrap($conf['renderWrap'], $conf['renderWrap.']) : $conf['renderWrap'];
280 $theValue .= $this->cObj->wrap($renderCode, $renderWrap);
281 $theValue = str_replace('###RESULT###', $theValue, $result);
282 } else {
283 $theValue = $this->cObj->cObjGetSingle($conf['noResultObj'], $conf['noResultObj.'], 'noResultObj');
284 }
285 $GLOBALS['TT']->setTSlogMessage('Search in fields: ' . $this->listOfSearchFields);
286 // Wrapping
287 $content = $theValue;
288 $wrap = isset($conf['wrap.']) ? $this->cObj->stdWrap($conf['wrap'], $conf['wrap.']) : $conf['wrap'];
289 if ($wrap) {
290 $content = $this->cObj->wrap($content, $wrap);
291 }
292 if (isset($conf['stdWrap.'])) {
293 $content = $this->cObj->stdWrap($content, $conf['stdWrap.']);
294 }
295 // Returning, do not cache the result of the search
296 $GLOBALS['TSFE']->set_no_cache('Search result page');
297 return $content;
298 }
299 return '';
300 }
301
302 /**
303 * Creates the $this->tables-array.
304 * 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.
305 *
306 * @param string $requestedCols is a list (-) of columns that we want to search. This could be input from the search-form (see TypoScript documentation)
307 * @param string $allowedCols $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.
308 * @return void
309 * @todo Define visibility
310 */
311 public function register_tables_and_columns($requestedCols, $allowedCols) {
312 $rCols = $this->explodeCols($requestedCols);
313 $aCols = $this->explodeCols($allowedCols);
314 foreach ($rCols as $k => $v) {
315 $rCols[$k] = trim($v);
316 if (in_array($rCols[$k], $aCols)) {
317 $parts = explode('.', $rCols[$k]);
318 $this->tables[$parts[0]]['searchfields'][] = $parts[1];
319 }
320 }
321 $this->tables['pages']['primary_key'] = 'uid';
322 $this->tables['pages']['resultfields'][] = 'uid';
323 unset($this->tables['pages']['fkey']);
324 foreach ($aCols as $k => $v) {
325 $aCols[$k] = trim($v);
326 $parts = explode('.', $aCols[$k]);
327 $this->tables[$parts[0]]['resultfields'][] = $parts[1] . ' AS ' . str_replace('.', '_', $aCols[$k]);
328 $this->tables[$parts[0]]['fkey'] = 'pid';
329 }
330 $this->fTable = '';
331 foreach ($this->tables as $t => $v) {
332 if ($t != 'pages') {
333 if (!$this->fTable) {
334 $this->fTable = $t;
335 } else {
336 unset($this->tables[$t]);
337 }
338 }
339 }
340 }
341
342 /**
343 * Function that can convert the syntax for entering which tables/fields the search should be conducted in.
344 *
345 * @param string $in This is the code-line defining the tables/fields to search. Syntax: '[table1].[field1]-[field2]-[field3] : [table2].[field1]-[field2]'
346 * @return array An array where the values is "[table].[field]" strings to search
347 * @see register_tables_and_columns()
348 * @todo Define visibility
349 */
350 public function explodeCols($in) {
351 $theArray = explode(':', $in);
352 $out = array();
353 foreach ($theArray as $val) {
354 $val = trim($val);
355 $parts = explode('.', $val);
356 if ($parts[0] && $parts[1]) {
357 $subparts = explode('-', $parts[1]);
358 foreach ($subparts as $piece) {
359 $piece = trim($piece);
360 if ($piece) {
361 $out[] = $parts[0] . '.' . $piece;
362 }
363 }
364 }
365 }
366 return $out;
367 }
368
369 /**
370 * Takes a search-string (WITHOUT SLASHES or else it'll be a little sppooky , NOW REMEMBER to unslash!!)
371 * Sets up $this->sword_array op with operators.
372 * This function uses $this->operator_translate_table as well as $this->default_operator
373 *
374 * @param string $sword The input search-word string.
375 * @return void
376 * @todo Define visibility
377 */
378 public function register_and_explode_search_string($sword) {
379 $sword = trim($sword);
380 if ($sword) {
381 $components = $this->split($sword);
382 // the searchword is stored here during the loop
383 $s_sword = '';
384 if (is_array($components)) {
385 $i = 0;
386 $lastoper = '';
387 foreach ($components as $key => $val) {
388 $operator = $this->get_operator($val);
389 if ($operator) {
390 $lastoper = $operator;
391 } elseif (strlen($val) > 1) {
392 // A searchword MUST be at least two characters long!
393 $this->sword_array[$i]['sword'] = $val;
394 $this->sword_array[$i]['oper'] = $lastoper ? $lastoper : $this->default_operator;
395 $lastoper = '';
396 $i++;
397 }
398 }
399 }
400 }
401 }
402
403 /**
404 * 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 ""
405 * This function could be re-written to be more clean and effective - yet it's not that important.
406 *
407 * @param string $origSword The raw sword string from outside
408 * @param string $specchars Special chars which are used as operators (+- is default)
409 * @param string $delchars Special chars which are deleted if the append the searchword (+-., is default)
410 * @return mixed Returns an ARRAY if there were search words, othervise the return value may be unset.
411 * @todo Define visibility
412 */
413 public function split($origSword, $specchars = '+-', $delchars = '+.,-') {
414 $sword = $origSword;
415 $specs = '[' . preg_quote($specchars, '/') . ']';
416 // As long as $sword is TRUE (that means $sword MUST be reduced little by little until its empty inside the loop!)
417 while ($sword) {
418 // There was a double-quote and we will then look for the ending quote.
419 if (preg_match('/^"/', $sword)) {
420 // Removes first double-quote
421 $sword = preg_replace('/^"/', '', $sword);
422 // Removes everything till next double-quote
423 preg_match('/^[^"]*/', $sword, $reg);
424 // reg[0] is the value, should not be trimmed
425 $value[] = $reg[0];
426 $sword = preg_replace('/^' . preg_quote($reg[0], '/') . '/', '', $sword);
427 // Removes last double-quote
428 $sword = trim(preg_replace('/^"/', '', $sword));
429 } elseif (preg_match('/^' . $specs . '/', $sword, $reg)) {
430 $value[] = $reg[0];
431 // Removes = sign
432 $sword = trim(preg_replace('/^' . $specs . '/', '', $sword));
433 } elseif (preg_match('/[\\+\\-]/', $sword)) {
434 // Check if $sword contains + or -
435 // + and - shall only be interpreted as $specchars when there's whitespace before it
436 // otherwise it's included in the searchword (e.g. "know-how")
437 // explode $sword to single words
438 $a_sword = explode(' ', $sword);
439 // get first word
440 $word = array_shift($a_sword);
441 // Delete $delchars at end of string
442 $word = rtrim($word, $delchars);
443 // add searchword to values
444 $value[] = $word;
445 // re-build $sword
446 $sword = implode(' ', $a_sword);
447 } else {
448 // There are no double-quotes around the value. Looking for next (space) or special char.
449 preg_match('/^[^ ' . preg_quote($specchars, '/') . ']*/', $sword, $reg);
450 // Delete $delchars at end of string
451 $word = rtrim(trim($reg[0]), $delchars);
452 $value[] = $word;
453 $sword = trim(preg_replace('/^' . preg_quote($reg[0], '/') . '/', '', $sword));
454 }
455 }
456 return $value;
457 }
458
459 /**
460 * This creates the search-query.
461 * In TypoScript this is used for searching only records not hidden, start/endtimed and fe_grouped! (enable-fields, see tt_content)
462 * Sets $this->queryParts
463 *
464 * @param string $endClause Some extra conditions that the search must match.
465 * @return boolean Returns TRUE no matter what - sweet isn't it!
466 * @access private
467 * @see \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::SEARCHRESULT()
468 * @todo Define visibility
469 */
470 public function build_search_query($endClause) {
471 if (is_array($this->tables)) {
472 $tables = $this->tables;
473 $primary_table = '';
474 // Primary key table is found.
475 foreach ($tables as $key => $val) {
476 if ($tables[$key]['primary_key']) {
477 $primary_table = $key;
478 }
479 }
480 if ($primary_table) {
481 // Initialize query parts:
482 $this->queryParts = array(
483 'SELECT' => '',
484 'FROM' => '',
485 'WHERE' => '',
486 'GROUPBY' => '',
487 'ORDERBY' => '',
488 'LIMIT' => ''
489 );
490 // Find tables / field names to select:
491 $fieldArray = array();
492 $tableArray = array();
493 foreach ($tables as $key => $val) {
494 $tableArray[] = $key;
495 $resultfields = $tables[$key]['resultfields'];
496 if (is_array($resultfields)) {
497 foreach ($resultfields as $key2 => $val2) {
498 $fieldArray[] = $key . '.' . $val2;
499 }
500 }
501 }
502 $this->queryParts['SELECT'] = implode(',', $fieldArray);
503 $this->queryParts['FROM'] = implode(',', $tableArray);
504 // Set join WHERE parts:
505 $whereArray = array();
506 $primary_table_and_key = $primary_table . '.' . $tables[$primary_table]['primary_key'];
507 $primKeys = array();
508 foreach ($tables as $key => $val) {
509 $fkey = $tables[$key]['fkey'];
510 if ($fkey) {
511 $primKeys[] = $key . '.' . $fkey . '=' . $primary_table_and_key;
512 }
513 }
514 if (count($primKeys)) {
515 $whereArray[] = '(' . implode(' OR ', $primKeys) . ')';
516 }
517 // Additional where clause:
518 if (trim($endClause)) {
519 $whereArray[] = trim($endClause);
520 }
521 // Add search word where clause:
522 $query_part = $this->build_search_query_for_searchwords();
523 if (!$query_part) {
524 $query_part = '(0!=0)';
525 }
526 $whereArray[] = '(' . $query_part . ')';
527 // Implode where clauses:
528 $this->queryParts['WHERE'] = implode(' AND ', $whereArray);
529 // Group by settings:
530 if ($this->group_by) {
531 if ($this->group_by == 'PRIMARY_KEY') {
532 $this->queryParts['GROUPBY'] = $primary_table_and_key;
533 } else {
534 $this->queryParts['GROUPBY'] = $this->group_by;
535 }
536 }
537 }
538 }
539 }
540
541 /**
542 * Creates the part of the SQL-sentence, that searches for the search-words ($this->sword_array)
543 *
544 * @return string Part of where class limiting result to the those having the search word.
545 * @access private
546 * @todo Define visibility
547 */
548 public function build_search_query_for_searchwords() {
549 if (is_array($this->sword_array)) {
550 $main_query_part = array();
551 foreach ($this->sword_array as $key => $val) {
552 $s_sword = $this->sword_array[$key]['sword'];
553 // Get subQueryPart
554 $sub_query_part = array();
555 $this->listOfSearchFields = '';
556 foreach ($this->tables as $key3 => $val3) {
557 $searchfields = $this->tables[$key3]['searchfields'];
558 if (is_array($searchfields)) {
559 foreach ($searchfields as $key2 => $val2) {
560 $this->listOfSearchFields .= $key3 . '.' . $val2 . ',';
561 $sub_query_part[] = $key3 . '.' . $val2 . ' LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($s_sword, $key3) . '%\'';
562 }
563 }
564 }
565 if (count($sub_query_part)) {
566 $main_query_part[] = $this->sword_array[$key]['oper'];
567 $main_query_part[] = '(' . implode(' OR ', $sub_query_part) . ')';
568 }
569 }
570 if (count($main_query_part)) {
571 // Remove first part anyways.
572 unset($main_query_part[0]);
573 return implode(' ', $main_query_part);
574 }
575 }
576 }
577
578 /**
579 * This returns an SQL search-operator (eg. AND, OR, NOT) translated from the current localized set of operators (eg. in danish OG, ELLER, IKKE).
580 *
581 * @param string $operator The possible operator to find in the internal operator array.
582 * @return string If found, the SQL operator for the localized input operator.
583 * @access private
584 * @todo Define visibility
585 */
586 public function get_operator($operator) {
587 $operator = trim($operator);
588 $op_array = $this->operator_translate_table;
589 if ($this->operator_translate_table_caseinsensitive) {
590 // case-conversion is charset insensitive, but it doesn't spoil
591 // anything if input string AND operator table is already converted
592 $operator = strtolower($operator);
593 }
594 foreach ($op_array as $key => $val) {
595 $item = $op_array[$key][0];
596 if ($this->operator_translate_table_caseinsensitive) {
597 // See note above.
598 $item = strtolower($item);
599 }
600 if ($operator == $item) {
601 return $op_array[$key][1];
602 }
603 }
604 }
605
606 /**
607 * Counts the results and sets the result in $this->res_count
608 *
609 * @return boolean TRUE, if $this->query was found
610 * @todo Define visibility
611 */
612 public function count_query() {
613 if (is_array($this->queryParts)) {
614 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($this->queryParts['SELECT'], $this->queryParts['FROM'], $this->queryParts['WHERE'], $this->queryParts['GROUPBY']);
615 $this->res_count = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
616 return TRUE;
617 }
618 }
619
620 /**
621 * Executes the search, sets result pointer in $this->result
622 *
623 * @return boolean TRUE, if $this->query was set and query performed
624 * @todo Define visibility
625 */
626 public function execute_query() {
627 if (is_array($this->queryParts)) {
628 $this->result = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($this->queryParts);
629 return TRUE;
630 }
631 }
632
633 /**
634 * Returns URL-parameters with the current search words.
635 * Used when linking to result pages so that search words can be highlighted.
636 *
637 * @return string URL-parameters with the searchwords
638 * @todo Define visibility
639 */
640 public function get_searchwords() {
641 $SWORD_PARAMS = '';
642 if (is_array($this->sword_array)) {
643 foreach ($this->sword_array as $key => $val) {
644 $SWORD_PARAMS .= '&sword_list[]=' . rawurlencode($val['sword']);
645 }
646 }
647 return $SWORD_PARAMS;
648 }
649
650 /**
651 * Returns an array with the search words in
652 *
653 * @return array IF the internal sword_array contained search words it will return these, otherwise "void
654 * @todo Define visibility
655 */
656 public function get_searchwordsArray() {
657 if (is_array($this->sword_array)) {
658 foreach ($this->sword_array as $key => $val) {
659 $swords[] = $val['sword'];
660 }
661 }
662 return $swords;
663 }
664
665 }