TYPO3 CMS  TYPO3_6-2
IndexSearchRepository.php
Go to the documentation of this file.
1 <?php
3 
17 
26 
32  protected $indexerObj;
33 
34  protected $externalParsers = array();
35 
36  protected $frontendUserGroupList = '';
37 
38  // formally known as $this->piVars['sections']
39  protected $sections = NULL;
40 
41  // formally known as $this->piVars['type']
42  protected $searchType = NULL;
43 
44  // formally known as $this->piVars['lang']
45  protected $languageUid = NULL;
46 
47  // formally known as $this->piVars['media']
48  protected $mediaType = NULL;
49 
50  // formally known as $this->piVars['sort_order']
51  protected $sortOrder = NULL;
52 
53  // formally known as $this->piVars['desc']
54  protected $descendingSortOrderFlag = NULL;
55 
56  // formally known as $this->piVars['pointer']
57  protected $resultpagePointer = 0;
58 
59  // formally known as $this->piVars['result']
60  protected $numberOfResults = 10;
61 
68 
75  protected $joinPagesForQuery = FALSE;
76 
77  // Select clauses for individual words,
78  // will be filled during the search
79  protected $wSelClauses = array();
80 
81  // formally known as $conf['search.']['exactCount']
82  // Continue counting and checking of results even if we are sure
83  // they are not displayed in this request. This will slow down your
84  // page rendering, but it allows precise search result counters.
85  // enabled through settings.exactCount
86  protected $useExactCount = FALSE;
87 
88  // formally known as $this->conf['show.']['forbiddenRecords']
89  // enabled through settings.displayForbiddenRecords
90  protected $displayForbiddenRecords = FALSE;
91 
92  // constants to help where to use wildcards in SQL like queries
93  const WILDCARD_LEFT = 1;
94  const WILDCARD_RIGHT = 2;
104  public function initialize($settings, $searchData, $externalParsers, $searchRootPageIdList) {
105  // Initialize the indexer-class - just to use a few function (for making hashes)
106  $this->indexerObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\IndexedSearch\\Indexer');
107  $this->externalParsers = $externalParsers;
108  $this->searchRootPageIdList = $searchRootPageIdList;
109  $this->frontendUserGroupList = $GLOBALS['TSFE']->gr_list;
110  // Should we use joinPagesForQuery instead of long lists of uids?
111  if ($settings['searchSkipExtendToSubpagesChecking']) {
112  $this->joinPagesForQuery = 1;
113  }
114  if ($settings['exactCount']) {
115  $this->useExactCount = TRUE;
116  }
117  if ($settings['displayForbiddenRecords']) {
118  $this->displayForbiddenRecords = TRUE;
119  }
120  $this->sections = $searchData['sections'];
121  $this->searchType = $searchData['searchType'];
122  $this->languageUid = $searchData['languageUid'];
123  $this->mediaType = isset($searchData['mediaType']) ? $searchData['mediaType'] : FALSE;
124  $this->sortOrder = $searchData['sortOrder'];
125  $this->descendingSortOrderFlag = $searchData['desc'];
126  $this->resultpagePointer = $searchData['pointer'];
127  if (isset($searchData['numberOfResults']) && is_numeric($searchData['numberOfResults'])) {
128  $this->numberOfResults = (int)$searchData['numberOfResults'];
129  }
130  }
131 
139  public function doSearch($searchWords, $freeIndexUid = -1) {
140  // Getting SQL result pointer:
141  $GLOBALS['TT']->push('Searching result');
142  if ($hookObj = &$this->hookRequest('getResultRows_SQLpointer')) {
143  $res = $hookObj->getResultRows_SQLpointer($searchWords, $freeIndexUid);
144  } else {
145  $res = $this->getResultRows_SQLpointer($searchWords, $freeIndexUid);
146  }
147  $GLOBALS['TT']->pull();
148  // Organize and process result:
149  if ($res) {
150  // Total search-result count
151  $count = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
152  // The pointer is set to the result page that is currently being viewed
153  $pointer = MathUtility::forceIntegerInRange($this->resultpagePointer, 0, floor($count / $this->numberOfResults));
154  // Initialize result accumulation variables:
155  $c = 0;
156  // Result pointer: Counts up the position in the current search-result
157  $grouping_phashes = array();
158  // Used to filter out duplicates.
159  $grouping_chashes = array();
160  // Used to filter out duplicates BASED ON cHash.
161  $firstRow = array();
162  // Will hold the first row in result - used to calculate relative hit-ratings.
163  $resultRows = array();
164  // Will hold the results rows for display.
165  // Now, traverse result and put the rows to be displayed into an array
166  // Each row should contain the fields from 'ISEC.*, IP.*' combined
167  // + artificial fields "show_resume" (boolean) and "result_number" (counter)
168  while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
169  // Set first row
170  if (!$c) {
171  $firstRow = $row;
172  }
173  // Tells whether we can link directly to a document
174  // or not (depends on possible right problems)
175  $row['show_resume'] = $this->checkResume($row);
176  $phashGr = !in_array($row['phash_grouping'], $grouping_phashes);
177  $chashGr = !in_array(($row['contentHash'] . '.' . $row['data_page_id']), $grouping_chashes);
178  if ($phashGr && $chashGr) {
179  // Only if the resume may be shown are we going to filter out duplicates...
180  if ($row['show_resume'] || $this->displayForbiddenRecords) {
181  // Only on documents which are not multiple pages documents
182  if (!$this->multiplePagesType($row['item_type'])) {
183  $grouping_phashes[] = $row['phash_grouping'];
184  }
185  $grouping_chashes[] = $row['contentHash'] . '.' . $row['data_page_id'];
186  // Increase the result pointer
187  $c++;
188  // All rows for display is put into resultRows[]
189  if ($c > $pointer * $this->numberOfResults && $c <= $pointer * $this->numberOfResults + $this->numberOfResults) {
190  $row['result_number'] = $c;
191  $resultRows[] = $row;
192  // This may lead to a problem: If the result check is not stopped here, the search will take longer.
193  // However the result counter will not filter out grouped cHashes/pHashes that were not processed yet.
194  // You can change this behavior using the "search.exactCount" property (see above).
195  if (!$this->useExactCount && $c + 1 > ($pointer + 1) * $this->numberOfResults) {
196  break;
197  }
198  }
199  } else {
200  // Skip this row if the user cannot
201  // view it (missing permission)
202  $count--;
203  }
204  } else {
205  // For each time a phash_grouping document is found
206  // (which is thus not displayed) the search-result count is reduced,
207  // so that it matches the number of rows displayed.
208  $count--;
209  }
210  }
211  return array(
212  'resultRows' => $resultRows,
213  'firstRow' => $firstRow,
214  'count' => $count
215  );
216  } else {
217  // No results found
218  return FALSE;
219  }
220  }
221 
229  protected function getResultRows_SQLpointer($searchWords, $freeIndexUid = -1) {
230  // This SEARCHES for the searchwords in $searchWords AND returns a
231  // COMPLETE list of phash-integers of the matches.
232  $list = $this->getPhashList($searchWords);
233  // Perform SQL Search / collection of result rows array:
234  if ($list) {
235  // Do the search:
236  $GLOBALS['TT']->push('execFinalQuery');
237  $res = $this->execFinalQuery($list, $freeIndexUid);
238  $GLOBALS['TT']->pull();
239  return $res;
240  } else {
241  return FALSE;
242  }
243  }
244 
245  /***********************************
246  *
247  * Helper functions on searching (SQL)
248  *
249  ***********************************/
257  protected function getPhashList($searchWords) {
258  // Initialize variables:
259  $c = 0;
260  // This array accumulates the phash-values
261  $totalHashList = array();
262  $this->wSelClauses = array();
263  // Traverse searchwords; for each, select all phash integers and merge/diff/intersect them with previous word (based on operator)
264  foreach ($searchWords as $k => $v) {
265  // Making the query for a single search word based on the search-type
266  $sWord = $v['sword'];
267  $theType = (string) $this->searchType;
268  // If there are spaces in the search-word, make a full text search instead.
269  if (strstr($sWord, ' ')) {
270  $theType = 20;
271  }
272  $GLOBALS['TT']->push('SearchWord "' . $sWord . '" - $theType=' . $theType);
273  $res = '';
274  // Perform search for word:
275  switch ($theType) {
276  case '1':
277  // Part of word
278  $res = $this->searchWord($sWord, self::WILDCARD_LEFT | self::WILDCARD_RIGHT);
279  break;
280  case '2':
281  // First part of word
282  $res = $this->searchWord($sWord, self::WILDCARD_RIGHT);
283  break;
284  case '3':
285  // Last part of word
286  $res = $this->searchWord($sWord, self::WILDCARD_LEFT);
287  break;
288  case '10':
289  // Sounds like
295  $indexerObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\IndexedSearch\\Indexer');
296  // Perform metaphone search
297  $storeMetaphoneInfoAsWords = !$this->isTableUsed('index_words');
298  $res = $this->searchMetaphone($indexerObj->metaphone($sWord, $storeMetaphoneInfoAsWords));
299  unset($indexerObj);
300  break;
301  case '20':
302  // Sentence
303  $res = $this->searchSentence($sWord);
304  // If there is a fulltext search for a sentence there is
305  // a likeliness that sorting cannot be done by the rankings
306  // from the rel-table (because no relations will exist for the
307  // sentence in the word-table). So therefore mtime is used instead.
308  // It is not required, but otherwise some hits may be left out.
309  $this->sortOrder = 'mtime';
310  break;
311  default:
312  // Distinct word
313  $res = $this->searchDistinct($sWord);
314  }
315  // If there was a query to do, then select all phash-integers which resulted from this.
316  if ($res) {
317  // Get phash list by searching for it:
318  $phashList = array();
319  while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
320  $phashList[] = $row['phash'];
321  }
322  $GLOBALS['TYPO3_DB']->sql_free_result($res);
323  // Here the phash list are merged with the existing result based on whether we are dealing with OR, NOT or AND operations.
324  if ($c) {
325  switch ($v['oper']) {
326  case 'OR':
327  $totalHashList = array_unique(array_merge($phashList, $totalHashList));
328  break;
329  case 'AND NOT':
330  $totalHashList = array_diff($totalHashList, $phashList);
331  break;
332  default:
333  // AND...
334  $totalHashList = array_intersect($totalHashList, $phashList);
335  }
336  } else {
337  // First search
338  $totalHashList = $phashList;
339  }
340  }
341  $GLOBALS['TT']->pull();
342  $c++;
343  }
344  return implode(',', $totalHashList);
345  }
346 
354  protected function execPHashListQuery($wordSel, $additionalWhereClause = '') {
355  return $GLOBALS['TYPO3_DB']->exec_SELECTquery('IR.phash', 'index_words IW,
356  index_rel IR,
357  index_section ISEC', $wordSel . '
358  AND IW.wid=IR.wid
359  AND ISEC.phash=IR.phash
360  ' . $this->sectionTableWhere() . '
361  ' . $additionalWhereClause, 'IR.phash');
362  }
363 
371  protected function searchWord($sWord, $mode) {
372  $wildcard_left = $mode & self::WILDCARD_LEFT ? '%' : '';
373  $wildcard_right = $mode & self::WILDCARD_RIGHT ? '%' : '';
374  $wSel = 'IW.baseword LIKE \'' . $wildcard_left . $GLOBALS['TYPO3_DB']->quoteStr($sWord, 'index_words') . $wildcard_right . '\'';
375  $this->wSelClauses[] = $wSel;
376  $res = $this->execPHashListQuery($wSel, ' AND is_stopword=0');
377  return $res;
378  }
379 
386  protected function searchDistinct($sWord) {
387  $wSel = 'IW.wid=' . $this->md5inthash($sWord);
388  $this->wSelClauses[] = $wSel;
389  $res = $this->execPHashListQuery($wSel, ' AND is_stopword=0');
390  return $res;
391  }
392 
399  protected function searchSentence($sWord) {
400  $this->wSelClauses[] = '1=1';
401  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('ISEC.phash', 'index_section ISEC, index_fulltext IFT', 'IFT.fulltextdata LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($sWord, 'index_fulltext') . '%\' AND
402  ISEC.phash = IFT.phash
403  ' . $this->sectionTableWhere(), 'ISEC.phash');
404  return $res;
405  }
406 
413  protected function searchMetaphone($sWord) {
414  $wSel = 'IW.metaphone=' . $sWord;
415  $this->wSelClauses[] = $wSel;
416  $res = $this->execPHashListQuery($wSel, ' AND is_stopword=0');
417  return $res;
418  }
419 
425  protected function sectionTableWhere() {
426  $whereClause = '';
427  $match = FALSE;
428  if (!($this->searchRootPageIdList < 0)) {
429  $whereClause = ' AND ISEC.rl0 IN (' . $this->searchRootPageIdList . ') ';
430  }
431  if (substr($this->sections, 0, 4) == 'rl1_') {
432  $list = implode(',', \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', substr($this->sections, 4)));
433  $whereClause .= ' AND ISEC.rl1 IN (' . $list . ')';
434  $match = TRUE;
435  } elseif (substr($this->sections, 0, 4) == 'rl2_') {
436  $list = implode(',', \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', substr($this->sections, 4)));
437  $whereClause .= ' AND ISEC.rl2 IN (' . $list . ')';
438  $match = TRUE;
439  } elseif (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields'])) {
440  // Traversing user configured fields to see if any of those are used to limit search to a section:
441  foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields'] as $fieldName => $rootLineLevel) {
442  if (substr($this->sections, 0, strlen($fieldName) + 1) == $fieldName . '_') {
443  $list = implode(',', \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', substr($this->sections, strlen($fieldName) + 1)));
444  $whereClause .= ' AND ISEC.' . $fieldName . ' IN (' . $list . ')';
445  $match = TRUE;
446  break;
447  }
448  }
449  }
450  // If no match above, test the static types:
451  if (!$match) {
452  switch ((string) $this->sections) {
453  case '-1':
454  $whereClause .= ' AND ISEC.page_id=' . $GLOBALS['TSFE']->id;
455  break;
456  case '-2':
457  $whereClause .= ' AND ISEC.rl2=0';
458  break;
459  case '-3':
460  $whereClause .= ' AND ISEC.rl2>0';
461  break;
462  }
463  }
464  return $whereClause;
465  }
466 
472  public function mediaTypeWhere() {
473  $whereClause = '';
474  switch ($this->mediaType) {
475  case '0':
476  // '0' => 'Kun TYPO3 sider',
477  $whereClause = ' AND IP.item_type=' . $GLOBALS['TYPO3_DB']->fullQuoteStr('0', 'index_phash');
478  break;
479  case '-2':
480  // All external documents
481  $whereClause = ' AND IP.item_type!=' . $GLOBALS['TYPO3_DB']->fullQuoteStr('0', 'index_phash');
482  break;
483  case FALSE:
484 
485  case '-1':
486  // All content
487  $whereClause = '';
488  break;
489  default:
490  $whereClause = ' AND IP.item_type=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->mediaType, 'index_phash');
491  }
492  return $whereClause;
493  }
494 
500  public function languageWhere() {
501  // -1 is the same as ALL language.
502  if ($this->languageUid >= 0) {
503  return ' AND IP.sys_language_uid=' . (int)$this->languageUid;
504  }
505  }
506 
513  public function freeIndexUidWhere($freeIndexUid) {
514  $freeIndexUid = (int)$freeIndexUid;
515  if ($freeIndexUid >= 0) {
516  // First, look if the freeIndexUid is a meta configuration:
517  $indexCfgRec = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('indexcfgs', 'index_config', 'type=5 AND uid=' . $freeIndexUid . $this->enableFields('index_config'));
518  if (is_array($indexCfgRec)) {
519  $refs = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $indexCfgRec['indexcfgs']);
520  // Default value to protect against empty array.
521  $list = array(-99);
522  foreach ($refs as $ref) {
523  list($table, $uid) = \TYPO3\CMS\Core\Utility\GeneralUtility::revExplode('_', $ref, 2);
524  $uid = (int)$uid;
525  switch ($table) {
526  case 'index_config':
527  $idxRec = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('uid', 'index_config', 'uid=' . $uid . $this->enableFields('index_config'));
528  if ($idxRec) {
529  $list[] = $uid;
530  }
531  break;
532  case 'pages':
533  $indexCfgRecordsFromPid = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid', 'index_config', 'pid=' . $uid . $this->enableFields('index_config'));
534  foreach ($indexCfgRecordsFromPid as $idxRec) {
535  $list[] = $idxRec['uid'];
536  }
537  break;
538  }
539  }
540  $list = array_unique($list);
541  } else {
542  $list = array($freeIndexUid);
543  }
544  return ' AND IP.freeIndexUid IN (' . implode(',', $list) . ')';
545  }
546  }
547 
555  protected function execFinalQuery($list, $freeIndexUid = -1) {
556  // Setting up methods of filtering results
557  // based on page types, access, etc.
558  $page_join = '';
559  $page_where = '';
560  // Indexing configuration clause:
561  $freeIndexUidClause = $this->freeIndexUidWhere($freeIndexUid);
562  // Calling hook for alternative creation of page ID list
563  if ($hookObj = $this->hookRequest('execFinalQuery_idList')) {
564  $page_where = $hookObj->execFinalQuery_idList($list);
565  } elseif ($this->joinPagesForQuery) {
566  // Alternative to getting all page ids by ->getTreeList() where
567  // "excludeSubpages" is NOT respected.
568  $page_join = ',
569  pages';
570  $page_where = 'pages.uid = ISEC.page_id
571  ' . $this->enableFields('pages') . '
572  AND pages.no_search=0
573  AND pages.doktype<200
574  ';
575  } elseif ($this->searchRootPageIdList >= 0) {
576  // Collecting all pages IDs in which to search;
577  // filtering out ALL pages that are not accessible due to enableFields.
578  // Does NOT look for "no_search" field!
579  $siteIdNumbers = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $this->searchRootPageIdList);
580  $pageIdList = array();
581  foreach ($siteIdNumbers as $rootId) {
582  $pageIdList[] = $GLOBALS['TSFE']->cObj->getTreeList(-1 * $rootId, 9999);
583  }
584  $page_where = 'ISEC.page_id IN (' . implode(',', $pageIdList) . ')';
585  } else {
586  // Disable everything... (select all)
587  $page_where = '1=1';
588  }
589  // otherwise select all / disable everything
590  // If any of the ranking sortings are selected, we must make a
591  // join with the word/rel-table again, because we need to
592  // calculate ranking based on all search-words found.
593  if (substr($this->sortOrder, 0, 5) == 'rank_') {
594  switch ($this->sortOrder) {
595  case 'rank_flag':
596  // This gives priority to word-position (max-value) so that words in title, keywords, description counts more than in content.
597  // The ordering is refined with the frequency sum as well.
598  $grsel = 'MAX(IR.flags) AS order_val1, SUM(IR.freq) AS order_val2';
599  $orderBy = 'order_val1' . $this->getDescendingSortOrderFlag() . ', order_val2' . $this->getDescendingSortOrderFlag();
600  break;
601  case 'rank_first':
602  // Results in average position of search words on page.
603  // Must be inversely sorted (low numbers are closer to top)
604  $grsel = 'AVG(IR.first) AS order_val';
605  $orderBy = 'order_val' . $this->getDescendingSortOrderFlag(TRUE);
606  break;
607  case 'rank_count':
608  // Number of words found
609  $grsel = 'SUM(IR.count) AS order_val';
610  $orderBy = 'order_val' . $this->getDescendingSortOrderFlag();
611  break;
612  default:
613  // Frequency sum. I'm not sure if this is the best way to do
614  // it (make a sum...). Or should it be the average?
615  $grsel = 'SUM(IR.freq) AS order_val';
616  $orderBy = 'order_val' . $this->getDescendingSortOrderFlag();
617  }
618  $wordSel = '';
619  if (!empty($this->wSelClauses)) {
620  // So, words are imploded into an OR statement (no "sentence search" should be done here - may deselect results)
621  $wordSel = '(' . implode(' OR ', $this->wSelClauses) . ') AND ';
622  }
623  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
624  'ISEC.*, IP.*, ' . $grsel,
625  'index_words IW,
626  index_rel IR,
627  index_section ISEC,
628  index_phash IP' . $page_join,
629  $wordSel .
630  'IP.phash IN (' . $list . ') ' .
631  $this->mediaTypeWhere() . ' ' . $this->languageWhere() . $freeIndexUidClause . '
632  AND IW.wid=IR.wid
633  AND ISEC.phash = IR.phash
634  AND IP.phash = IR.phash
635  AND ' . $page_where,
636  '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',
637  $orderBy
638  );
639  } else {
640  // Otherwise, if sorting are done with the pages table or other fields,
641  // there is no need for joining with the rel/word tables:
642  $orderBy = '';
643  switch ((string) $this->sortOrder) {
644  case 'title':
645  $orderBy = 'IP.item_title' . $this->getDescendingSortOrderFlag();
646  break;
647  case 'crdate':
648  $orderBy = 'IP.item_crdate' . $this->getDescendingSortOrderFlag();
649  break;
650  case 'mtime':
651  $orderBy = 'IP.item_mtime' . $this->getDescendingSortOrderFlag();
652  break;
653  }
654  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('ISEC.*, IP.*', 'index_phash IP,index_section ISEC' . $page_join, 'IP.phash IN (' . $list . ') ' . $this->mediaTypeWhere() . $this->languageWhere() . $freeIndexUidClause . '
655  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);
656  }
657  return $res;
658  }
659 
668  protected function checkResume($row) {
669  // If the record is indexed by an indexing configuration, just show it.
670  // At least this is needed for external URLs and files.
671  // For records we might need to extend this - for instance block display if record is access restricted.
672  if ($row['freeIndexUid']) {
673  return TRUE;
674  }
675  // Evaluate regularly indexed pages based on item_type:
676  // External media:
677  if ($row['item_type']) {
678  // For external media we will check the access of the parent page on which the media was linked from.
679  // "phash_t3" is the phash of the parent TYPO3 page row which initiated the indexing of the documents in this section.
680  // So, selecting for the grlist records belonging to the parent phash-row where the current users gr_list exists will help us to know.
681  // 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.
682  if ($this->isTableUsed('index_grlist')) {
683  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('phash', 'index_grlist', 'phash=' . (int)$row['phash_t3'] . ' AND gr_list=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->frontendUserGroupList, 'index_grlist'));
684  } else {
685  $res = FALSE;
686  }
687  if ($res && $GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
688  return TRUE;
689  } else {
690  return FALSE;
691  }
692  } else {
693  // Ordinary TYPO3 pages:
694  if ((string)$row['gr_list'] !== (string)$this->frontendUserGroupList) {
695  // 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...
696  if ($this->isTableUsed('index_grlist')) {
697  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('phash', 'index_grlist', 'phash=' . (int)$row['phash'] . ' AND gr_list=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->frontendUserGroupList, 'index_grlist'));
698  } else {
699  $res = FALSE;
700  }
701  if ($res && $GLOBALS['TYPO3_DB']->sql_num_rows($res)) {
702  return TRUE;
703  } else {
704  return FALSE;
705  }
706  } else {
707  return TRUE;
708  }
709  }
710  }
711 
720  protected function getDescendingSortOrderFlag($inverse = FALSE) {
722  if ($inverse) {
723  $desc = !$desc;
724  }
725  return !$desc ? ' DESC' : '';
726  }
727 
743  protected function enableFields($table) {
744  return $GLOBALS['TSFE']->sys_page->enableFields($table, $table == 'pages' ? $GLOBALS['TSFE']->showHiddenPage : $GLOBALS['TSFE']->showHiddenRecords);
745  }
746 
753  protected function multiplePagesType($itemType) {
754  return is_object($this->externalParsers[$itemType]) && $this->externalParsers[$itemType]->isMultiplePageExtension($itemType);
755  }
756 
766  protected function md5inthash($str) {
767  return \TYPO3\CMS\IndexedSearch\Utility\IndexedSearchUtility::md5inthash($str);
768  }
769 
778  protected function isTableUsed($table_list) {
779  return \TYPO3\CMS\IndexedSearch\Utility\IndexedSearchUtility::isTableUsed($table_list);
780  }
781 
788  public function hookRequest($functionName) {
789  // Hook: menuConfig_preProcessModMenu
790  if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]) {
791  $hookObj = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]);
792  if (method_exists($hookObj, $functionName)) {
793  $hookObj->pObj = $this;
794  return $hookObj;
795  }
796  }
797  }
798 
805  public function getSearchType() {
806  return (int)$this->searchType;
807  }
808 
814  public function getSearchRootPageIdList() {
815  return \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $this->searchRootPageIdList);
816  }
817 
824  public function getJoinPagesForQuery() {
826  }
827 }
initialize($settings, $searchData, $externalParsers, $searchRootPageIdList)
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:32
static intExplode($delimiter, $string, $removeEmptyValues=FALSE, $limit=0)
$uid
Definition: server.php:36
static getUserObj($classRef, $checkPrefix='', $silent=FALSE)
static trimExplode($delim, $string, $removeEmptyValues=FALSE, $limit=0)
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
static revExplode($delimiter, $string, $count=0)