TYPO3 CMS  TYPO3_7-6
IndexSearchRepository.php
Go to the documentation of this file.
1 <?php
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 
21 
26 {
32  protected $indexerObj;
33 
39  protected $externalParsers = [];
40 
46  protected $frontendUserGroupList = '';
47 
54  protected $sections = null;
55 
62  protected $searchType = null;
63 
70  protected $languageUid = null;
71 
78  protected $mediaType = null;
79 
86  protected $sortOrder = null;
87 
94  protected $descendingSortOrderFlag = null;
95 
102  protected $resultpagePointer = 0;
103 
110  protected $numberOfResults = 10;
111 
120 
127  protected $joinPagesForQuery = false;
128 
134  protected $wSelClauses = [];
135 
147  protected $useExactCount = false;
148 
157  protected $displayForbiddenRecords = false;
158 
168  public function initialize($settings, $searchData, $externalParsers, $searchRootPageIdList)
169  {
170  // Initialize the indexer-class - just to use a few function (for making hashes)
171  $this->indexerObj = GeneralUtility::makeInstance(Indexer::class);
172  $this->externalParsers = $externalParsers;
173  $this->searchRootPageIdList = $searchRootPageIdList;
174  $this->frontendUserGroupList = $this->getTypoScriptFrontendController()->gr_list;
175  // Should we use joinPagesForQuery instead of long lists of uids?
176  if ($settings['searchSkipExtendToSubpagesChecking']) {
177  $this->joinPagesForQuery = 1;
178  }
179  if ($settings['exactCount']) {
180  $this->useExactCount = true;
181  }
182  if ($settings['displayForbiddenRecords']) {
183  $this->displayForbiddenRecords = true;
184  }
185  $this->sections = $searchData['sections'];
186  $this->searchType = $searchData['searchType'];
187  $this->languageUid = $searchData['languageUid'];
188  $this->mediaType = isset($searchData['mediaType']) ? $searchData['mediaType'] : false;
189  $this->sortOrder = $searchData['sortOrder'];
190  $this->descendingSortOrderFlag = $searchData['desc'];
191  $this->resultpagePointer = $searchData['pointer'];
192  if (isset($searchData['numberOfResults']) && is_numeric($searchData['numberOfResults'])) {
193  $this->numberOfResults = (int)$searchData['numberOfResults'];
194  }
195  }
196 
204  public function doSearch($searchWords, $freeIndexUid = -1)
205  {
206  // Getting SQL result pointer:
207  $this->getTimeTracker()->push('Searching result');
208  if ($hookObj = &$this->hookRequest('getResultRows_SQLpointer')) {
209  $res = $hookObj->getResultRows_SQLpointer($searchWords, $freeIndexUid);
210  } else {
211  $res = $this->getResultRows_SQLpointer($searchWords, $freeIndexUid);
212  }
213  $this->getTimeTracker()->pull();
214  // Organize and process result:
215  if ($res) {
216  // Total search-result count
217  $count = $this->getDatabaseConnection()->sql_num_rows($res);
218  // The pointer is set to the result page that is currently being viewed
219  $pointer = MathUtility::forceIntegerInRange($this->resultpagePointer, 0, floor($count / $this->numberOfResults));
220  // Initialize result accumulation variables:
221  $c = 0;
222  // Result pointer: Counts up the position in the current search-result
223  $grouping_phashes = [];
224  // Used to filter out duplicates.
225  $grouping_chashes = [];
226  // Used to filter out duplicates BASED ON cHash.
227  $firstRow = [];
228  // Will hold the first row in result - used to calculate relative hit-ratings.
229  $resultRows = [];
230  // Will hold the results rows for display.
231  // Now, traverse result and put the rows to be displayed into an array
232  // Each row should contain the fields from 'ISEC.*, IP.*' combined
233  // + artificial fields "show_resume" (bool) and "result_number" (counter)
234  while ($row = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
235  // Set first row
236  if (!$c) {
237  $firstRow = $row;
238  }
239  // Tells whether we can link directly to a document
240  // or not (depends on possible right problems)
241  $row['show_resume'] = $this->checkResume($row);
242  $phashGr = !in_array($row['phash_grouping'], $grouping_phashes);
243  $chashGr = !in_array(($row['contentHash'] . '.' . $row['data_page_id']), $grouping_chashes);
244  if ($phashGr && $chashGr) {
245  // Only if the resume may be shown are we going to filter out duplicates...
246  if ($row['show_resume'] || $this->displayForbiddenRecords) {
247  // Only on documents which are not multiple pages documents
248  if (!$this->multiplePagesType($row['item_type'])) {
249  $grouping_phashes[] = $row['phash_grouping'];
250  }
251  $grouping_chashes[] = $row['contentHash'] . '.' . $row['data_page_id'];
252  // Increase the result pointer
253  $c++;
254  // All rows for display is put into resultRows[]
255  if ($c > $pointer * $this->numberOfResults && $c <= $pointer * $this->numberOfResults + $this->numberOfResults) {
256  $row['result_number'] = $c;
257  $resultRows[] = $row;
258  // This may lead to a problem: If the result check is not stopped here, the search will take longer.
259  // However the result counter will not filter out grouped cHashes/pHashes that were not processed yet.
260  // You can change this behavior using the "search.exactCount" property (see above).
261  if (!$this->useExactCount && $c + 1 > ($pointer + 1) * $this->numberOfResults) {
262  break;
263  }
264  }
265  } else {
266  // Skip this row if the user cannot
267  // view it (missing permission)
268  $count--;
269  }
270  } else {
271  // For each time a phash_grouping document is found
272  // (which is thus not displayed) the search-result count is reduced,
273  // so that it matches the number of rows displayed.
274  $count--;
275  }
276  }
277 
278  $this->getDatabaseConnection()->sql_free_result($res);
279 
280  return [
281  'resultRows' => $resultRows,
282  'firstRow' => $firstRow,
283  'count' => $count
284  ];
285  } else {
286  // No results found
287  return false;
288  }
289  }
290 
298  protected function getResultRows_SQLpointer($searchWords, $freeIndexUid = -1)
299  {
300  // This SEARCHES for the searchwords in $searchWords AND returns a
301  // COMPLETE list of phash-integers of the matches.
302  $list = $this->getPhashList($searchWords);
303  // Perform SQL Search / collection of result rows array:
304  if ($list) {
305  // Do the search:
306  $this->getTimeTracker()->push('execFinalQuery');
307  $res = $this->execFinalQuery($list, $freeIndexUid);
308  $this->getTimeTracker()->pull();
309  return $res;
310  } else {
311  return false;
312  }
313  }
314 
315  /***********************************
316  *
317  * Helper functions on searching (SQL)
318  *
319  ***********************************/
327  protected function getPhashList($searchWords)
328  {
329  // Initialize variables:
330  $c = 0;
331  // This array accumulates the phash-values
332  $totalHashList = [];
333  $this->wSelClauses = [];
334  // Traverse searchwords; for each, select all phash integers and merge/diff/intersect them with previous word (based on operator)
335  foreach ($searchWords as $k => $v) {
336  // Making the query for a single search word based on the search-type
337  $sWord = $v['sword'];
338  $theType = (string)$this->searchType;
339  // If there are spaces in the search-word, make a full text search instead.
340  if (strstr($sWord, ' ')) {
341  $theType = 20;
342  }
343  $this->getTimeTracker()->push('SearchWord "' . $sWord . '" - $theType=' . $theType);
344  // Perform search for word:
345  switch ($theType) {
346  case '1':
347  // Part of word
348  $res = $this->searchWord($sWord, Utility\LikeWildcard::BOTH);
349  break;
350  case '2':
351  // First part of word
352  $res = $this->searchWord($sWord, Utility\LikeWildcard::RIGHT);
353  break;
354  case '3':
355  // Last part of word
356  $res = $this->searchWord($sWord, Utility\LikeWildcard::LEFT);
357  break;
358  case '10':
359  // Sounds like
365  $indexerObj = GeneralUtility::makeInstance(Indexer::class);
366  // Perform metaphone search
367  $storeMetaphoneInfoAsWords = !$this->isTableUsed('index_words');
368  $res = $this->searchMetaphone($indexerObj->metaphone($sWord, $storeMetaphoneInfoAsWords));
369  unset($indexerObj);
370  break;
371  case '20':
372  // Sentence
373  $res = $this->searchSentence($sWord);
374  // If there is a fulltext search for a sentence there is
375  // a likeliness that sorting cannot be done by the rankings
376  // from the rel-table (because no relations will exist for the
377  // sentence in the word-table). So therefore mtime is used instead.
378  // It is not required, but otherwise some hits may be left out.
379  $this->sortOrder = 'mtime';
380  break;
381  default:
382  // Distinct word
383  $res = $this->searchDistinct($sWord);
384  }
385  // If there was a query to do, then select all phash-integers which resulted from this.
386  if ($res) {
387  // Get phash list by searching for it:
388  $phashList = [];
389  while ($row = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
390  $phashList[] = $row['phash'];
391  }
392  $this->getDatabaseConnection()->sql_free_result($res);
393  // Here the phash list are merged with the existing result based on whether we are dealing with OR, NOT or AND operations.
394  if ($c) {
395  switch ($v['oper']) {
396  case 'OR':
397  $totalHashList = array_unique(array_merge($phashList, $totalHashList));
398  break;
399  case 'AND NOT':
400  $totalHashList = array_diff($totalHashList, $phashList);
401  break;
402  default:
403  // AND...
404  $totalHashList = array_intersect($totalHashList, $phashList);
405  }
406  } else {
407  // First search
408  $totalHashList = $phashList;
409  }
410  }
411  $this->getTimeTracker()->pull();
412  $c++;
413  }
414  return implode(',', $totalHashList);
415  }
416 
424  protected function execPHashListQuery($wordSel, $additionalWhereClause = '')
425  {
426  return $this->getDatabaseConnection()->exec_SELECTquery(
427  'IR.phash',
428  'index_words IW, index_rel IR, index_section ISEC',
429  $wordSel . ' AND IW.wid=IR.wid AND ISEC.phash=IR.phash' . $this->sectionTableWhere() . $additionalWhereClause,
430  'IR.phash'
431  );
432  }
433 
441  protected function searchWord($sWord, $wildcard)
442  {
443  $likeWildcard = Utility\LikeWildcard::cast($wildcard);
444  $wSel = $likeWildcard->getLikeQueryPart(
445  'index_words',
446  'IW.baseword',
447  $sWord
448  );
449  $this->wSelClauses[] = $wSel;
450  return $this->execPHashListQuery($wSel, ' AND is_stopword=0');
451  }
452 
459  protected function searchDistinct($sWord)
460  {
461  $wSel = 'IW.wid=' . $this->md5inthash($sWord);
462  $this->wSelClauses[] = $wSel;
463  return $this->execPHashListQuery($wSel, ' AND is_stopword=0');
464  }
465 
472  protected function searchSentence($sWord)
473  {
474  $this->wSelClauses[] = '1=1';
475  $likeWildcard = Utility\LikeWildcard::cast(Utility\LikeWildcard::BOTH);
476  $likePart = $likeWildcard->getLikeQueryPart(
477  'index_fulltext',
478  'IFT.fulltextdata',
479  $sWord
480  );
481 
482  return $this->getDatabaseConnection()->exec_SELECTquery(
483  'ISEC.phash',
484  'index_section ISEC, index_fulltext IFT',
485  $likePart . ' AND ISEC.phash = IFT.phash' . $this->sectionTableWhere(),
486  'ISEC.phash'
487  );
488  }
489 
496  protected function searchMetaphone($sWord)
497  {
498  $wSel = 'IW.metaphone=' . $sWord;
499  $this->wSelClauses[] = $wSel;
500  return $this->execPHashListQuery($wSel, ' AND is_stopword=0');
501  }
502 
508  public function sectionTableWhere()
509  {
510  $whereClause = '';
511  $match = false;
512  if (!($this->searchRootPageIdList < 0)) {
513  $whereClause = ' AND ISEC.rl0 IN (' . $this->searchRootPageIdList . ') ';
514  }
515  if (substr($this->sections, 0, 4) == 'rl1_') {
516  $list = implode(',', GeneralUtility::intExplode(',', substr($this->sections, 4)));
517  $whereClause .= ' AND ISEC.rl1 IN (' . $list . ')';
518  $match = true;
519  } elseif (substr($this->sections, 0, 4) == 'rl2_') {
520  $list = implode(',', GeneralUtility::intExplode(',', substr($this->sections, 4)));
521  $whereClause .= ' AND ISEC.rl2 IN (' . $list . ')';
522  $match = true;
523  } elseif (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields'])) {
524  // Traversing user configured fields to see if any of those are used to limit search to a section:
525  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields'] as $fieldName => $rootLineLevel) {
526  if (substr($this->sections, 0, strlen($fieldName) + 1) == $fieldName . '_') {
527  $list = implode(',', GeneralUtility::intExplode(',', substr($this->sections, strlen($fieldName) + 1)));
528  $whereClause .= ' AND ISEC.' . $fieldName . ' IN (' . $list . ')';
529  $match = true;
530  break;
531  }
532  }
533  }
534  // If no match above, test the static types:
535  if (!$match) {
536  switch ((string)$this->sections) {
537  case '-1':
538  $whereClause .= ' AND ISEC.page_id=' . $this->getTypoScriptFrontendController()->id;
539  break;
540  case '-2':
541  $whereClause .= ' AND ISEC.rl2=0';
542  break;
543  case '-3':
544  $whereClause .= ' AND ISEC.rl2>0';
545  break;
546  }
547  }
548  return $whereClause;
549  }
550 
556  public function mediaTypeWhere()
557  {
558  switch ($this->mediaType) {
559  case '0':
560  // '0' => 'Kun TYPO3 sider',
561  $whereClause = ' AND IP.item_type=' . $this->getDatabaseConnection()->fullQuoteStr('0', 'index_phash');
562  break;
563  case '-2':
564  // All external documents
565  $whereClause = ' AND IP.item_type!=' . $this->getDatabaseConnection()->fullQuoteStr('0', 'index_phash');
566  break;
567  case false:
568 
569  case '-1':
570  // All content
571  $whereClause = '';
572  break;
573  default:
574  $whereClause = ' AND IP.item_type=' . $this->getDatabaseConnection()->fullQuoteStr($this->mediaType, 'index_phash');
575  }
576  return $whereClause;
577  }
578 
584  public function languageWhere()
585  {
586  // -1 is the same as ALL language.
587  if ($this->languageUid >= 0) {
588  return ' AND IP.sys_language_uid=' . (int)$this->languageUid;
589  }
590  return '';
591  }
592 
599  public function freeIndexUidWhere($freeIndexUid)
600  {
601  $freeIndexUid = (int)$freeIndexUid;
602  if ($freeIndexUid >= 0) {
603  // First, look if the freeIndexUid is a meta configuration:
604  $indexCfgRec = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('indexcfgs', 'index_config', 'type=5 AND uid=' . $freeIndexUid . $this->enableFields('index_config'));
605  if (is_array($indexCfgRec)) {
606  $refs = GeneralUtility::trimExplode(',', $indexCfgRec['indexcfgs']);
607  // Default value to protect against empty array.
608  $list = [-99];
609  foreach ($refs as $ref) {
610  list($table, $uid) = GeneralUtility::revExplode('_', $ref, 2);
611  $uid = (int)$uid;
612  switch ($table) {
613  case 'index_config':
614  $idxRec = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('uid', 'index_config', 'uid=' . $uid . $this->enableFields('index_config'));
615  if ($idxRec) {
616  $list[] = $uid;
617  }
618  break;
619  case 'pages':
620  $indexCfgRecordsFromPid = $this->getDatabaseConnection()->exec_SELECTgetRows('uid', 'index_config', 'pid=' . $uid . $this->enableFields('index_config'));
621  foreach ($indexCfgRecordsFromPid as $idxRec) {
622  $list[] = $idxRec['uid'];
623  }
624  break;
625  }
626  }
627  $list = array_unique($list);
628  } else {
629  $list = [$freeIndexUid];
630  }
631  return ' AND IP.freeIndexUid IN (' . implode(',', $list) . ')';
632  }
633  return '';
634  }
635 
643  protected function execFinalQuery($list, $freeIndexUid = -1)
644  {
645  // Setting up methods of filtering results
646  // based on page types, access, etc.
647  $page_join = '';
648  // Indexing configuration clause:
649  $freeIndexUidClause = $this->freeIndexUidWhere($freeIndexUid);
650  // Calling hook for alternative creation of page ID list
651  if ($hookObj = $this->hookRequest('execFinalQuery_idList')) {
652  $page_where = $hookObj->execFinalQuery_idList($list);
653  } elseif ($this->joinPagesForQuery) {
654  // Alternative to getting all page ids by ->getTreeList() where
655  // "excludeSubpages" is NOT respected.
656  $page_join = ',
657  pages';
658  $page_where = 'pages.uid = ISEC.page_id
659  ' . $this->enableFields('pages') . '
660  AND pages.no_search=0
661  AND pages.doktype<200
662  ';
663  } elseif ($this->searchRootPageIdList >= 0) {
664  // Collecting all pages IDs in which to search;
665  // filtering out ALL pages that are not accessible due to enableFields.
666  // Does NOT look for "no_search" field!
667  $siteIdNumbers = GeneralUtility::intExplode(',', $this->searchRootPageIdList);
668  $pageIdList = [];
669  foreach ($siteIdNumbers as $rootId) {
670  $pageIdList[] = $this->getTypoScriptFrontendController()->cObj->getTreeList(-1 * $rootId, 9999);
671  }
672  $page_where = 'ISEC.page_id IN (' . implode(',', $pageIdList) . ')';
673  } else {
674  // Disable everything... (select all)
675  $page_where = '1=1';
676  }
677  // otherwise select all / disable everything
678  // If any of the ranking sortings are selected, we must make a
679  // join with the word/rel-table again, because we need to
680  // calculate ranking based on all search-words found.
681  if (substr($this->sortOrder, 0, 5) === 'rank_') {
682  switch ($this->sortOrder) {
683  case 'rank_flag':
684  // This gives priority to word-position (max-value) so that words in title, keywords, description counts more than in content.
685  // The ordering is refined with the frequency sum as well.
686  $grsel = 'MAX(IR.flags) AS order_val1, SUM(IR.freq) AS order_val2';
687  $orderBy = 'order_val1' . $this->getDescendingSortOrderFlag() . ', order_val2' . $this->getDescendingSortOrderFlag();
688  break;
689  case 'rank_first':
690  // Results in average position of search words on page.
691  // Must be inversely sorted (low numbers are closer to top)
692  $grsel = 'AVG(IR.first) AS order_val';
693  $orderBy = 'order_val' . $this->getDescendingSortOrderFlag(true);
694  break;
695  case 'rank_count':
696  // Number of words found
697  $grsel = 'SUM(IR.count) AS order_val';
698  $orderBy = 'order_val' . $this->getDescendingSortOrderFlag();
699  break;
700  default:
701  // Frequency sum. I'm not sure if this is the best way to do
702  // it (make a sum...). Or should it be the average?
703  $grsel = 'SUM(IR.freq) AS order_val';
704  $orderBy = 'order_val' . $this->getDescendingSortOrderFlag();
705  }
706  $wordSel = '';
707  if (!empty($this->wSelClauses)) {
708  // So, words are imploded into an OR statement (no "sentence search" should be done here - may deselect results)
709  $wordSel = '(' . implode(' OR ', $this->wSelClauses) . ') AND ';
710  }
711  $res = $this->getDatabaseConnection()->exec_SELECTquery(
712  'ISEC.*, IP.*, ' . $grsel,
713  'index_words IW,
714  index_rel IR,
715  index_section ISEC,
716  index_phash IP' . $page_join,
717  $wordSel .
718  'IP.phash IN (' . $list . ') ' .
719  $this->mediaTypeWhere() . ' ' . $this->languageWhere() . $freeIndexUidClause . '
720  AND IW.wid=IR.wid
721  AND ISEC.phash = IR.phash
722  AND IP.phash = IR.phash
723  AND ' . $page_where,
724  'IP.phash,ISEC.phash,ISEC.phash_t3,ISEC.rl0,ISEC.rl1,ISEC.rl2 ,ISEC.page_id,ISEC.uniqid,IP.phash_grouping,IP.data_filename ,IP.data_page_id ,IP.data_page_reg1,IP.data_page_type,IP.data_page_mp,IP.gr_list,IP.item_type,IP.item_title,IP.item_description,IP.item_mtime,IP.tstamp,IP.item_size,IP.contentHash,IP.crdate,IP.parsetime,IP.sys_language_uid,IP.item_crdate,IP.cHashParams,IP.externalUrl,IP.recordUid,IP.freeIndexUid,IP.freeIndexSetId',
725  $orderBy
726  );
727  } else {
728  // Otherwise, if sorting are done with the pages table or other fields,
729  // there is no need for joining with the rel/word tables:
730  $orderBy = '';
731  switch ((string)$this->sortOrder) {
732  case 'title':
733  $orderBy = 'IP.item_title' . $this->getDescendingSortOrderFlag();
734  break;
735  case 'crdate':
736  $orderBy = 'IP.item_crdate' . $this->getDescendingSortOrderFlag();
737  break;
738  case 'mtime':
739  $orderBy = 'IP.item_mtime' . $this->getDescendingSortOrderFlag();
740  break;
741  }
742  $res = $this->getDatabaseConnection()->exec_SELECTquery('ISEC.*, IP.*', 'index_phash IP,index_section ISEC' . $page_join, 'IP.phash IN (' . $list . ') ' . $this->mediaTypeWhere() . $this->languageWhere() . $freeIndexUidClause . '
743  AND IP.phash = ISEC.phash AND ' . $page_where, 'IP.phash,ISEC.phash,ISEC.phash_t3,ISEC.rl0,ISEC.rl1,ISEC.rl2 ,ISEC.page_id,ISEC.uniqid,IP.phash_grouping,IP.data_filename ,IP.data_page_id ,IP.data_page_reg1,IP.data_page_type,IP.data_page_mp,IP.gr_list,IP.item_type,IP.item_title,IP.item_description,IP.item_mtime,IP.tstamp,IP.item_size,IP.contentHash,IP.crdate,IP.parsetime,IP.sys_language_uid,IP.item_crdate,IP.cHashParams,IP.externalUrl,IP.recordUid,IP.freeIndexUid,IP.freeIndexSetId', $orderBy);
744  }
745  return $res;
746  }
747 
756  protected function checkResume($row)
757  {
758  // If the record is indexed by an indexing configuration, just show it.
759  // At least this is needed for external URLs and files.
760  // For records we might need to extend this - for instance block display if record is access restricted.
761  if ($row['freeIndexUid']) {
762  return true;
763  }
764  // Evaluate regularly indexed pages based on item_type:
765  // External media:
766  if ($row['item_type']) {
767  // For external media we will check the access of the parent page on which the media was linked from.
768  // "phash_t3" is the phash of the parent TYPO3 page row which initiated the indexing of the documents in this section.
769  // So, selecting for the grlist records belonging to the parent phash-row where the current users gr_list exists will help us to know.
770  // If this is NOT found, there is still a theoretical possibility that another user accessible page would display a link, so maybe the resume of such a document here may be unjustified hidden. But better safe than sorry.
771  if ($this->isTableUsed('index_grlist')) {
772  $res = $this->getDatabaseConnection()->exec_SELECTquery('phash', 'index_grlist', 'phash=' . (int)$row['phash_t3'] . ' AND gr_list=' . $this->getDatabaseConnection()->fullQuoteStr($this->frontendUserGroupList, 'index_grlist'));
773  } else {
774  $res = false;
775  }
776  if ($res && $this->getDatabaseConnection()->sql_num_rows($res)) {
777  return true;
778  } else {
779  return false;
780  }
781  } else {
782  // Ordinary TYPO3 pages:
783  if ((string)$row['gr_list'] !== (string)$this->frontendUserGroupList) {
784  // Selecting for the grlist records belonging to the phash-row where the current users gr_list exists. If it is found it is proof that this user has direct access to the phash-rows content although he did not himself initiate the indexing...
785  if ($this->isTableUsed('index_grlist')) {
786  $res = $this->getDatabaseConnection()->exec_SELECTquery('phash', 'index_grlist', 'phash=' . (int)$row['phash'] . ' AND gr_list=' . $this->getDatabaseConnection()->fullQuoteStr($this->frontendUserGroupList, 'index_grlist'));
787  } else {
788  $res = false;
789  }
790  if ($res && $this->getDatabaseConnection()->sql_num_rows($res)) {
791  return true;
792  } else {
793  return false;
794  }
795  } else {
796  return true;
797  }
798  }
799  }
800 
809  protected function getDescendingSortOrderFlag($inverse = false)
810  {
812  if ($inverse) {
813  $desc = !$desc;
814  }
815  return !$desc ? ' DESC' : '';
816  }
817 
832  protected function enableFields($table)
833  {
834  return $this->getTypoScriptFrontendController()->sys_page->enableFields($table, $table === 'pages' ? $this->getTypoScriptFrontendController()->showHiddenPage : $this->getTypoScriptFrontendController()->showHiddenRecords);
835  }
836 
843  protected function multiplePagesType($itemType)
844  {
846  $fileContentParser = $this->externalParsers[$itemType];
847  return is_object($fileContentParser) && $fileContentParser->isMultiplePageExtension($itemType);
848  }
849 
859  protected function md5inthash($str)
860  {
862  }
863 
872  protected function isTableUsed($table_list)
873  {
874  return Utility\IndexedSearchUtility::isTableUsed($table_list);
875  }
876 
883  public function hookRequest($functionName)
884  {
885  // Hook: menuConfig_preProcessModMenu
886  if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]) {
887  $hookObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]);
888  if (method_exists($hookObj, $functionName)) {
889  $hookObj->pObj = $this;
890  return $hookObj;
891  }
892  }
893  return null;
894  }
895 
902  public function getSearchType()
903  {
904  return (int)$this->searchType;
905  }
906 
912  public function getSearchRootPageIdList()
913  {
914  return GeneralUtility::intExplode(',', $this->searchRootPageIdList);
915  }
916 
923  public function getJoinPagesForQuery()
924  {
926  }
927 
933  protected function getDatabaseConnection()
934  {
935  return $GLOBALS['TYPO3_DB'];
936  }
937 
941  protected function getTypoScriptFrontendController()
942  {
943  return $GLOBALS['TSFE'];
944  }
945 
949  protected function getTimeTracker()
950  {
951  return $GLOBALS['TT'];
952  }
953 }
initialize($settings, $searchData, $externalParsers, $searchRootPageIdList)
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
$uid
Definition: server.php:38
static revExplode($delimiter, $string, $count=0)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']