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