‪TYPO3CMS  9.5
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 
17 use Doctrine\DBAL\Driver\Statement;
29 
35 {
41  protected ‪$indexerObj;
42 
48  protected ‪$externalParsers = [];
49 
55  protected ‪$frontendUserGroupList = '';
56 
63  protected ‪$sections;
64 
71  protected ‪$searchType;
72 
79  protected ‪$languageUid;
80 
87  protected ‪$mediaType;
88 
95  protected ‪$sortOrder;
96 
103  protected ‪$descendingSortOrderFlag;
104 
111  protected ‪$resultpagePointer = 0;
112 
119  protected ‪$numberOfResults = 10;
120 
128  protected ‪$searchRootPageIdList;
129 
136  protected ‪$joinPagesForQuery = false;
137 
143  protected ‪$wSelClauses = [];
144 
156  protected ‪$useExactCount = false;
157 
166  protected ‪$displayForbiddenRecords = false;
167 
176  public function ‪initialize($settings, $searchData, ‪$externalParsers, ‪$searchRootPageIdList)
177  {
178  // Initialize the indexer-class - just to use a few function (for making hashes)
179  $this->indexerObj = GeneralUtility::makeInstance(Indexer::class);
180  $this->externalParsers = ‪$externalParsers;
181  $this->searchRootPageIdList = ‪$searchRootPageIdList;
182  $this->frontendUserGroupList = implode(',', GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('frontend.user', 'groupIds', [0, -1]));
183  // Should we use joinPagesForQuery instead of long lists of uids?
184  if ($settings['searchSkipExtendToSubpagesChecking']) {
185  $this->joinPagesForQuery = 1;
186  }
187  if ($settings['exactCount']) {
188  $this->useExactCount = true;
189  }
190  if ($settings['displayForbiddenRecords']) {
191  $this->displayForbiddenRecords = true;
192  }
193  $this->sections = $searchData['sections'];
194  $this->searchType = $searchData['searchType'];
195  $this->languageUid = $searchData['languageUid'];
196  $this->mediaType = $searchData['mediaType'] ?? false;
197  $this->sortOrder = $searchData['sortOrder'];
198  $this->descendingSortOrderFlag = $searchData['desc'];
199  $this->resultpagePointer = $searchData['pointer'];
200  if (isset($searchData['numberOfResults']) && is_numeric($searchData['numberOfResults'])) {
201  $this->numberOfResults = (int)$searchData['numberOfResults'];
202  }
203  }
204 
212  public function ‪doSearch($searchWords, $freeIndexUid = -1)
213  {
214  $useMysqlFulltext = (bool)GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('indexed_search', 'useMysqlFulltext');
215  // Getting SQL result pointer:
216  $this->‪getTimeTracker()->‪push('Searching result');
217  if ($hookObj = &$this->‪hookRequest('getResultRows_SQLpointer')) {
218  $result = $hookObj->getResultRows_SQLpointer($searchWords, $freeIndexUid);
219  } elseif ($useMysqlFulltext) {
220  $result = $this->‪getResultRows_SQLpointerMysqlFulltext($searchWords, $freeIndexUid);
221  } else {
222  $result = $this->‪getResultRows_SQLpointer($searchWords, $freeIndexUid);
223  }
224  $this->‪getTimeTracker()->‪pull();
225  // Organize and process result:
226  if ($result) {
227  // Total search-result count
228  $count = $result->rowCount();
229  // The pointer is set to the result page that is currently being viewed
230  $pointer = ‪MathUtility::forceIntegerInRange($this->resultpagePointer, 0, floor($count / $this->numberOfResults));
231  // Initialize result accumulation variables:
232  $c = 0;
233  // Result pointer: Counts up the position in the current search-result
234  $grouping_phashes = [];
235  // Used to filter out duplicates.
236  $grouping_chashes = [];
237  // Used to filter out duplicates BASED ON cHash.
238  $firstRow = [];
239  // Will hold the first row in result - used to calculate relative hit-ratings.
240  $resultRows = [];
241  // Will hold the results rows for display.
242  // Now, traverse result and put the rows to be displayed into an array
243  // Each row should contain the fields from 'ISEC.*, IP.*' combined
244  // + artificial fields "show_resume" (bool) and "result_number" (counter)
245  while ($row = $result->fetch()) {
246  // Set first row
247  if (!$c) {
248  $firstRow = $row;
249  }
250  // Tells whether we can link directly to a document
251  // or not (depends on possible right problems)
252  $row['show_resume'] = $this->‪checkResume($row);
253  $phashGr = !in_array($row['phash_grouping'], $grouping_phashes);
254  $chashGr = !in_array($row['contentHash'] . '.' . $row['data_page_id'], $grouping_chashes);
255  if ($phashGr && $chashGr) {
256  // Only if the resume may be shown are we going to filter out duplicates...
257  if ($row['show_resume'] || $this->displayForbiddenRecords) {
258  // Only on documents which are not multiple pages documents
259  if (!$this->‪multiplePagesType($row['item_type'])) {
260  $grouping_phashes[] = $row['phash_grouping'];
261  }
262  $grouping_chashes[] = $row['contentHash'] . '.' . $row['data_page_id'];
263  // Increase the result pointer
264  $c++;
265  // All rows for display is put into resultRows[]
266  if ($c > $pointer * $this->numberOfResults && $c <= $pointer * $this->numberOfResults + $this->numberOfResults) {
267  $row['result_number'] = $c;
268  $resultRows[] = $row;
269  // This may lead to a problem: If the result check is not stopped here, the search will take longer.
270  // However the result counter will not filter out grouped cHashes/pHashes that were not processed yet.
271  // You can change this behavior using the "settings.exactCount" property (see above).
272  if (!$this->useExactCount && $c + 1 > ($pointer + 1) * $this->numberOfResults) {
273  break;
274  }
275  }
276  } else {
277  // Skip this row if the user cannot
278  // view it (missing permission)
279  $count--;
280  }
281  } else {
282  // For each time a phash_grouping document is found
283  // (which is thus not displayed) the search-result count is reduced,
284  // so that it matches the number of rows displayed.
285  $count--;
286  }
287  }
288 
289  $result->closeCursor();
290 
291  return [
292  'resultRows' => $resultRows,
293  'firstRow' => $firstRow,
294  'count' => $count
295  ];
296  }
297  // No results found
298  return false;
299  }
300 
308  protected function ‪getResultRows_SQLpointer($searchWords, $freeIndexUid = -1)
309  {
310  // This SEARCHES for the searchwords in $searchWords AND returns a
311  // COMPLETE list of phash-integers of the matches.
312  $list = $this->getPhashList($searchWords);
313  // Perform SQL Search / collection of result rows array:
314  if ($list) {
315  // Do the search:
316  $this->‪getTimeTracker()->‪push('execFinalQuery');
317  $res = $this->‪execFinalQuery($list, $freeIndexUid);
318  $this->‪getTimeTracker()->‪pull();
319  return $res;
320  }
321  return false;
322  }
323 
333  protected function ‪getResultRows_SQLpointerMysqlFulltext($searchWordsArray, $freeIndexUid = -1)
334  {
335  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('index_fulltext');
336  if (strpos($connection->getServerVersion(), 'MySQL') !== 0) {
337  throw new \RuntimeException(
338  'Extension indexed_search is configured to use mysql fulltext, but table \'index_fulltext\''
339  . ' is running on a different DBMS.',
340  1472585525
341  );
342  }
343  // Build the search string, detect which fulltext index to use, and decide whether boolean search is needed or not
344  $searchData = $this->‪getSearchString($searchWordsArray);
345  // Perform SQL Search / collection of result rows array:
346  $resource = false;
347  if ($searchData) {
349  $timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
350  // Do the search:
351  $timeTracker->push('execFinalQuery');
352  $resource = $this->‪execFinalQuery_fulltext($searchData, $freeIndexUid);
353  $timeTracker->pull();
354  }
355  return $resource;
356  }
357 
366  protected function ‪getSearchString($searchWordArray)
367  {
368  // Initialize variables:
369  $count = 0;
370  // Change this to TRUE to force BOOLEAN SEARCH MODE (useful if fulltext index is still empty)
371  $searchBoolean = false;
372  $fulltextIndex = 'index_fulltext.fulltextdata';
373  // This holds the result if the search is natural (doesn't contain any boolean operators)
374  $naturalSearchString = '';
375  // This holds the result if the search is boolen (contains +/-/| operators)
376  $booleanSearchString = '';
377 
378  ‪$searchType = (string)$this->‪getSearchType();
379 
380  // Traverse searchwords and prefix them with corresponding operator
381  foreach ($searchWordArray as $searchWordData) {
382  // Making the query for a single search word based on the search-type
383  $searchWord = $searchWordData['sword'];
384  $wildcard = '';
385  if (strstr($searchWord, ' ')) {
386  ‪$searchType = '20';
387  }
388  switch (‪$searchType) {
389  case '1':
390  case '2':
391  case '3':
392  // First part of word
393  $wildcard = '*';
394  // Part-of-word search requires boolean mode!
395  $searchBoolean = true;
396  break;
397  case '10':
398  ‪$indexerObj = GeneralUtility::makeInstance(Indexer::class);
399  // Initialize the indexer-class
401  $searchWord = ‪$indexerObj->‪metaphone($searchWord, ‪$indexerObj->storeMetaphoneInfoAsWords);
402  unset(‪$indexerObj);
403  $fulltextIndex = 'index_fulltext.metaphonedata';
404  break;
405  case '20':
406  $searchBoolean = true;
407  // Remove existing quotes and fix misplaced quotes.
408  $searchWord = trim(str_replace('"', ' ', $searchWord));
409  break;
410  }
411  // Perform search for word:
412  switch ($searchWordData['oper']) {
413  case 'AND NOT':
414  $booleanSearchString .= ' -' . $searchWord . $wildcard;
415  $searchBoolean = true;
416  break;
417  case 'OR':
418  $booleanSearchString .= ' ' . $searchWord . $wildcard;
419  $searchBoolean = true;
420  break;
421  default:
422  $booleanSearchString .= ' +' . $searchWord . $wildcard;
423  $naturalSearchString .= ' ' . $searchWord;
424  }
425  $count++;
426  }
427  if (‪$searchType == '20') {
428  $searchString = '"' . trim($naturalSearchString) . '"';
429  } elseif ($searchBoolean) {
430  $searchString = trim($booleanSearchString);
431  } else {
432  $searchString = trim($naturalSearchString);
433  }
434  return [
435  'searchBoolean' => $searchBoolean,
436  'searchString' => $searchString,
437  'fulltextIndex' => $fulltextIndex
438  ];
439  }
440 
450  protected function ‪execFinalQuery_fulltext($searchData, $freeIndexUid = -1)
451  {
452  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_fulltext');
453  $queryBuilder->getRestrictions()->removeAll();
454  $queryBuilder->select('index_fulltext.*', 'ISEC.*', 'IP.*')
455  ->from('index_fulltext')
456  ->join(
457  'index_fulltext',
458  'index_phash',
459  'IP',
460  $queryBuilder->expr()->eq('index_fulltext.phash', $queryBuilder->quoteIdentifier('IP.phash'))
461  )
462  ->join(
463  'IP',
464  'index_section',
465  'ISEC',
466  $queryBuilder->expr()->eq('IP.phash', $queryBuilder->quoteIdentifier('ISEC.phash'))
467  );
468 
469  // Calling hook for alternative creation of page ID list
471  if ($hookObj = &$this->‪hookRequest('execFinalQuery_idList')) {
472  $pageWhere = $hookObj->execFinalQuery_idList('');
473  $queryBuilder->andWhere(‪QueryHelper::stripLogicalOperatorPrefix($pageWhere));
474  } elseif ($this->joinPagesForQuery) {
475  // Alternative to getting all page ids by ->getTreeList() where "excludeSubpages" is NOT respected.
476  $queryBuilder
477  ->join(
478  'ISEC',
479  'pages',
480  'pages',
481  $queryBuilder->expr()->eq('ISEC.page_id', $queryBuilder->quoteIdentifier('pages.uid'))
482  )
483  ->andWhere(
484  $queryBuilder->expr()->eq(
485  'pages.no_search',
486  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
487  )
488  )
489  ->andWhere(
490  $queryBuilder->expr()->lt(
491  'pages.doktype',
492  $queryBuilder->createNamedParameter(200, \PDO::PARAM_INT)
493  )
494  );
495  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
496  } elseif (‪$searchRootPageIdList[0] >= 0) {
497  // Collecting all pages IDs in which to search;
498  // filtering out ALL pages that are not accessible due to restriction containers. Does NOT look for "no_search" field!
499  $idList = [];
500  foreach (‪$searchRootPageIdList as $rootId) {
502  $cObj = GeneralUtility::makeInstance(\‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class);
503  $idList[] = $cObj->getTreeList(-1 * $rootId, 9999);
504  }
505  $idList = GeneralUtility::intExplode(',', implode(',', $idList));
506  $queryBuilder->andWhere(
507  $queryBuilder->expr()->in(
508  'ISEC.page_id',
509  $queryBuilder->createNamedParameter($idList, Connection::PARAM_INT_ARRAY)
510  )
511  );
512  }
513 
514  $searchBoolean = '';
515  if ($searchData['searchBoolean']) {
516  $searchBoolean = ' IN BOOLEAN MODE';
517  }
518  $queryBuilder->andWhere(
519  'MATCH (' . $queryBuilder->quoteIdentifier($searchData['fulltextIndex']) . ')'
520  . ' AGAINST (' . $queryBuilder->createNamedParameter($searchData['searchString'])
521  . $searchBoolean
522  . ')'
523  );
524 
525  $queryBuilder->andWhere(
530  );
531 
532  $queryBuilder->groupBy(
533  'IP.phash',
534  'ISEC.phash',
535  'ISEC.phash_t3',
536  'ISEC.rl0',
537  'ISEC.rl1',
538  'ISEC.rl2',
539  'ISEC.page_id',
540  'ISEC.uniqid',
541  'IP.phash_grouping',
542  'IP.data_filename',
543  'IP.data_page_id',
544  // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Remove along with database field data_page_reg1
545  'IP.data_page_reg1',
546  'IP.data_page_type',
547  'IP.data_page_mp',
548  'IP.gr_list',
549  'IP.item_type',
550  'IP.item_title',
551  'IP.item_description',
552  'IP.item_mtime',
553  'IP.tstamp',
554  'IP.item_size',
555  'IP.contentHash',
556  'IP.crdate',
557  'IP.parsetime',
558  'IP.sys_language_uid',
559  'IP.item_crdate',
560  'IP.cHashParams',
561  'IP.externalUrl',
562  'IP.recordUid',
563  'IP.freeIndexUid',
564  'IP.freeIndexSetId'
565  );
566 
567  return $queryBuilder->execute();
568  }
569 
570  /***********************************
571  *
572  * Helper functions on searching (SQL)
573  *
574  ***********************************/
582  protected function getPhashList($searchWords)
583  {
584  // Initialize variables:
585  $c = 0;
586  // This array accumulates the phash-values
587  $totalHashList = [];
588  $this->wSelClauses = [];
589  // Traverse searchwords; for each, select all phash integers and merge/diff/intersect them with previous word (based on operator)
590  foreach ($searchWords as $k => $v) {
591  // Making the query for a single search word based on the search-type
592  $sWord = $v['sword'];
593  $theType = (string)$this->searchType;
594  // If there are spaces in the search-word, make a full text search instead.
595  if (strstr($sWord, ' ')) {
596  $theType = 20;
597  }
598  $this->‪getTimeTracker()->‪push('SearchWord "' . $sWord . '" - $theType=' . $theType);
599  // Perform search for word:
600  switch ($theType) {
601  case '1':
602  // Part of word
603  $res = $this->‪searchWord($sWord, Utility\‪LikeWildcard::BOTH);
604  break;
605  case '2':
606  // First part of word
607  $res = $this->‪searchWord($sWord, Utility\‪LikeWildcard::RIGHT);
608  break;
609  case '3':
610  // Last part of word
611  $res = $this->‪searchWord($sWord, Utility\‪LikeWildcard::LEFT);
612  break;
613  case '10':
614  // Sounds like
620  ‪$indexerObj = GeneralUtility::makeInstance(Indexer::class);
621  // Perform metaphone search
622  $storeMetaphoneInfoAsWords = !$this->‪isTableUsed('index_words');
623  $res = $this->‪searchMetaphone($indexerObj->‪metaphone($sWord, $storeMetaphoneInfoAsWords));
624  unset(‪$indexerObj);
625  break;
626  case '20':
627  // Sentence
628  $res = $this->‪searchSentence($sWord);
629  // If there is a fulltext search for a sentence there is
630  // a likeliness that sorting cannot be done by the rankings
631  // from the rel-table (because no relations will exist for the
632  // sentence in the word-table). So therefore mtime is used instead.
633  // It is not required, but otherwise some hits may be left out.
634  $this->sortOrder = 'mtime';
635  break;
636  default:
637  // Distinct word
638  $res = $this->‪searchDistinct($sWord);
639  }
640  // If there was a query to do, then select all phash-integers which resulted from this.
641  if ($res) {
642  // Get phash list by searching for it:
643  $phashList = [];
644  while ($row = $res->fetch()) {
645  $phashList[] = $row['phash'];
646  }
647  // Here the phash list are merged with the existing result based on whether we are dealing with OR, NOT or AND operations.
648  if ($c) {
649  switch ($v['oper']) {
650  case 'OR':
651  $totalHashList = array_unique(array_merge($phashList, $totalHashList));
652  break;
653  case 'AND NOT':
654  $totalHashList = array_diff($totalHashList, $phashList);
655  break;
656  default:
657  // AND...
658  $totalHashList = array_intersect($totalHashList, $phashList);
659  }
660  } else {
661  // First search
662  $totalHashList = $phashList;
663  }
664  }
665  $this->‪getTimeTracker()->‪pull();
666  $c++;
667  }
668  return implode(',', $totalHashList);
669  }
670 
678  protected function ‪execPHashListQuery($wordSel, $additionalWhereClause = '')
679  {
680  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_words');
681  $queryBuilder->select('IR.phash')
682  ->from('index_words', 'IW')
683  ->from('index_rel', 'IR')
684  ->from('index_section', 'ISEC')
685  ->where(
687  $queryBuilder->expr()->eq('IW.wid', $queryBuilder->quoteIdentifier('IR.wid')),
688  $queryBuilder->expr()->eq('ISEC.phash', $queryBuilder->quoteIdentifier('IR.phash')),
689  ‪QueryHelper::stripLogicalOperatorPrefix($this->sectionTableWhere()),
690  ‪QueryHelper::stripLogicalOperatorPrefix($additionalWhereClause)
691  )
692  ->groupBy('IR.phash');
693 
694  return $queryBuilder->execute();
695  }
696 
704  protected function ‪searchWord($sWord, $wildcard)
705  {
706  $likeWildcard = ‪Utility\LikeWildcard::cast($wildcard);
707  $wSel = $likeWildcard->getLikeQueryPart(
708  'index_words',
709  'IW.baseword',
710  $sWord
711  );
712  $this->wSelClauses[] = $wSel;
713  return $this->‪execPHashListQuery($wSel, ' AND is_stopword=0');
714  }
715 
722  protected function ‪searchDistinct($sWord)
723  {
724  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
725  ->getQueryBuilderForTable('index_words')
726  ->expr();
727  $wSel = $expressionBuilder->eq('IW.wid', $this->‪md5inthash($sWord));
728  $this->wSelClauses[] = $wSel;
729  return $this->‪execPHashListQuery($wSel, $expressionBuilder->eq('is_stopword', 0));
730  }
731 
738  protected function ‪searchSentence($sWord)
739  {
740  $this->wSelClauses[] = '1=1';
741  $likeWildcard = ‪Utility\LikeWildcard::cast(Utility\‪LikeWildcard::BOTH);
742  $likePart = $likeWildcard->getLikeQueryPart(
743  'index_fulltext',
744  'IFT.fulltextdata',
745  $sWord
746  );
747 
748  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_section');
749  return $queryBuilder->select('ISEC.phash')
750  ->from('index_section', 'ISEC')
751  ->from('index_fulltext', 'IFT')
752  ->where(
754  $queryBuilder->expr()->eq('ISEC.phash', $queryBuilder->quoteIdentifier('IFT.phash')),
755  ‪QueryHelper::stripLogicalOperatorPrefix($this->sectionTableWhere())
756  )
757  ->groupBy('ISEC.phash')
758  ->execute();
759  }
760 
767  protected function ‪searchMetaphone($sWord)
768  {
769  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
770  ->getQueryBuilderForTable('index_words')
771  ->expr();
772  $wSel = $expressionBuilder->eq('IW.metaphone', $expressionBuilder->literal($sWord));
773  $this->wSelClauses[] = $wSel;
774  return $this->‪execPHashListQuery($wSel, $expressionBuilder->eq('is_stopword', 0));
775  }
776 
782  public function ‪sectionTableWhere()
783  {
784  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
785  ->getQueryBuilderForTable('index_section')
786  ->expr();
787 
788  $whereClause = $expressionBuilder->andX();
789  $match = false;
790  if (!($this->searchRootPageIdList < 0)) {
791  $whereClause->add(
792  $expressionBuilder->in('ISEC.rl0', GeneralUtility::intExplode(',', $this->searchRootPageIdList, true))
793  );
794  }
795  if (strpos($this->sections, 'rl1_') === 0) {
796  $whereClause->add(
797  $expressionBuilder->in('ISEC.rl1', GeneralUtility::intExplode(',', substr($this->sections, 4)))
798  );
799  $match = true;
800  } elseif (strpos($this->sections, 'rl2_') === 0) {
801  $whereClause->add(
802  $expressionBuilder->in('ISEC.rl2', GeneralUtility::intExplode(',', substr($this->sections, 4)))
803  );
804  $match = true;
805  } else {
806  // Traversing user configured fields to see if any of those are used to limit search to a section:
807  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['addRootLineFields'] ?? [] as $fieldName => $rootLineLevel) {
808  if (strpos($this->sections, $fieldName . '_') === 0) {
809  $whereClause->add(
810  $expressionBuilder->in(
811  'ISEC.' . $fieldName,
812  GeneralUtility::intExplode(',', substr($this->sections, strlen($fieldName) + 1))
813  )
814  );
815  $match = true;
816  break;
817  }
818  }
819  }
820  // If no match above, test the static types:
821  if (!$match) {
822  switch ((string)$this->sections) {
823  case '-1':
824  $whereClause->add(
825  $expressionBuilder->eq('ISEC.page_id', (int)$this->getTypoScriptFrontendController()->id)
826  );
827  break;
828  case '-2':
829  $whereClause->add($expressionBuilder->eq('ISEC.rl2', 0));
830  break;
831  case '-3':
832  $whereClause->add($expressionBuilder->gt('ISEC.rl2', 0));
833  break;
834  }
835  }
836 
837  return $whereClause->count() ? ' AND ' . $whereClause : '';
838  }
839 
845  public function ‪mediaTypeWhere()
846  {
847  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
848  ->getQueryBuilderForTable('index_phash')
849  ->expr();
850  switch ($this->mediaType) {
851  case '0':
852  // '0' => 'only TYPO3 pages',
853  $whereClause = $expressionBuilder->eq('IP.item_type', $expressionBuilder->literal('0'));
854  break;
855  case '-2':
856  // All external documents
857  $whereClause = $expressionBuilder->neq('IP.item_type', $expressionBuilder->literal('0'));
858  break;
859  case false:
860  // Intentional fall-through
861  case '-1':
862  // All content
863  $whereClause = '';
864  break;
865  default:
866  $whereClause = $expressionBuilder->eq('IP.item_type', $expressionBuilder->literal($this->mediaType));
867  }
868  return $whereClause ? ' AND ' . $whereClause : '';
869  }
870 
876  public function ‪languageWhere()
877  {
878  // -1 is the same as ALL language.
879  if ($this->languageUid < 0) {
880  return '';
881  }
882 
883  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
884  ->getQueryBuilderForTable('index_phash')
885  ->expr();
886 
887  return ' AND ' . $expressionBuilder->eq('IP.sys_language_uid', (int)$this->languageUid);
888  }
889 
896  public function ‪freeIndexUidWhere($freeIndexUid)
897  {
898  $freeIndexUid = (int)$freeIndexUid;
899  if ($freeIndexUid < 0) {
900  return '';
901  }
902  // First, look if the freeIndexUid is a meta configuration:
903  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
904  ->getQueryBuilderForTable('index_config');
905  $indexCfgRec = $queryBuilder->select('indexcfgs')
906  ->from('index_config')
907  ->where(
908  $queryBuilder->expr()->eq('type', $queryBuilder->createNamedParameter(5, \PDO::PARAM_INT)),
909  $queryBuilder->expr()->eq(
910  'uid',
911  $queryBuilder->createNamedParameter($freeIndexUid, \PDO::PARAM_INT)
912  )
913  )
914  ->execute()
915  ->fetch();
916 
917  if (is_array($indexCfgRec)) {
918  $refs = GeneralUtility::trimExplode(',', $indexCfgRec['indexcfgs']);
919  // Default value to protect against empty array.
920  $list = [-99];
921  foreach ($refs as $ref) {
922  list($table, $uid) = GeneralUtility::revExplode('_', $ref, 2);
923  $uid = (int)$uid;
924  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
925  ->getQueryBuilderForTable('index_config');
926  $queryBuilder->select('uid')
927  ->from('index_config');
928  switch ($table) {
929  case 'index_config':
930  $idxRec = $queryBuilder
931  ->where(
932  $queryBuilder->expr()->eq(
933  'uid',
934  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
935  )
936  )
937  ->execute()
938  ->fetch();
939  if ($idxRec) {
940  $list[] = $uid;
941  }
942  break;
943  case 'pages':
944  $indexCfgRecordsFromPid = $queryBuilder
945  ->where(
946  $queryBuilder->expr()->eq(
947  'pid',
948  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
949  )
950  )
951  ->execute();
952  while ($idxRec = $indexCfgRecordsFromPid->fetch()) {
953  $list[] = $idxRec['uid'];
954  }
955  break;
956  }
957  }
958  $list = array_unique($list);
959  } else {
960  $list = [$freeIndexUid];
961  }
962 
963  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
964  ->getQueryBuilderForTable('index_phash')
965  ->expr();
966  return ' AND ' . $expressionBuilder->in('IP.freeIndexUid', array_map('intval', $list));
967  }
968 
976  protected function ‪execFinalQuery($list, $freeIndexUid = -1)
977  {
978  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_words');
979  $queryBuilder->select('ISEC.*', 'IP.*')
980  ->from('index_phash', 'IP')
981  ->from('index_section', 'ISEC')
982  ->where(
983  $queryBuilder->expr()->in(
984  'IP.phash',
985  $queryBuilder->createNamedParameter(
986  GeneralUtility::intExplode(',', $list, true),
987  Connection::PARAM_INT_ARRAY
988  )
989  ),
990  ‪QueryHelper::stripLogicalOperatorPrefix($this->mediaTypeWhere()),
991  ‪QueryHelper::stripLogicalOperatorPrefix($this->languageWhere()),
992  ‪QueryHelper::stripLogicalOperatorPrefix($this->freeIndexUidWhere($freeIndexUid)),
993  $queryBuilder->expr()->eq('ISEC.phash', $queryBuilder->quoteIdentifier('IP.phash'))
994  )
995  ->groupBy(
996  'IP.phash',
997  'ISEC.phash',
998  'ISEC.phash_t3',
999  'ISEC.rl0',
1000  'ISEC.rl1',
1001  'ISEC.rl2',
1002  'ISEC.page_id',
1003  'ISEC.uniqid',
1004  'IP.phash_grouping',
1005  'IP.data_filename',
1006  'IP.data_page_id',
1007  // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Remove along with database field data_page_reg1
1008  'IP.data_page_reg1',
1009  'IP.data_page_type',
1010  'IP.data_page_mp',
1011  'IP.gr_list',
1012  'IP.item_type',
1013  'IP.item_title',
1014  'IP.item_description',
1015  'IP.item_mtime',
1016  'IP.tstamp',
1017  'IP.item_size',
1018  'IP.contentHash',
1019  'IP.crdate',
1020  'IP.parsetime',
1021  'IP.sys_language_uid',
1022  'IP.item_crdate',
1023  'IP.cHashParams',
1024  'IP.externalUrl',
1025  'IP.recordUid',
1026  'IP.freeIndexUid',
1027  'IP.freeIndexSetId',
1028  'IP.static_page_arguments'
1029  );
1030 
1031  // Setting up methods of filtering results
1032  // based on page types, access, etc.
1033  if ($hookObj = $this->‪hookRequest('execFinalQuery_idList')) {
1034  // Calling hook for alternative creation of page ID list
1035  $hookWhere = ‪QueryHelper::stripLogicalOperatorPrefix($hookObj->execFinalQuery_idList($list));
1036  if (!empty($hookWhere)) {
1037  $queryBuilder->andWhere($hookWhere);
1038  }
1039  } elseif ($this->joinPagesForQuery) {
1040  // Alternative to getting all page ids by ->getTreeList() where
1041  // "excludeSubpages" is NOT respected.
1042  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
1043  $queryBuilder->from('pages');
1044  $queryBuilder->andWhere(
1045  $queryBuilder->expr()->eq('pages.uid', $queryBuilder->quoteIdentifier('ISEC.page_id')),
1046  $queryBuilder->expr()->eq(
1047  'pages.no_search',
1048  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
1049  ),
1050  $queryBuilder->expr()->lt(
1051  'pages.doktype',
1052  $queryBuilder->createNamedParameter(200, \PDO::PARAM_INT)
1053  )
1054  );
1055  } elseif ($this->searchRootPageIdList >= 0) {
1056  // Collecting all pages IDs in which to search;
1057  // filtering out ALL pages that are not accessible due to restriction containers.
1058  // Does NOT look for "no_search" field!
1059  $siteIdNumbers = GeneralUtility::intExplode(',', $this->searchRootPageIdList);
1060  $pageIdList = [];
1061  foreach ($siteIdNumbers as $rootId) {
1062  $pageIdList[] = $this->‪getTypoScriptFrontendController()->cObj->getTreeList(-1 * $rootId, 9999);
1063  }
1064  $queryBuilder->andWhere(
1065  $queryBuilder->expr()->in(
1066  'ISEC.page_id',
1067  $queryBuilder->createNamedParameter(
1068  array_unique(GeneralUtility::intExplode(',', implode(',', $pageIdList), true)),
1069  Connection::PARAM_INT_ARRAY
1070  )
1071  )
1072  );
1073  }
1074  // otherwise select all / disable everything
1075  // If any of the ranking sortings are selected, we must make a
1076  // join with the word/rel-table again, because we need to
1077  // calculate ranking based on all search-words found.
1078  if (strpos($this->sortOrder, 'rank_') === 0) {
1079  $queryBuilder
1080  ->from('index_words', 'IW')
1081  ->from('index_rel', 'IR')
1082  ->andWhere(
1083  $queryBuilder->expr()->eq('IW.wid', $queryBuilder->quoteIdentifier('IR.wid')),
1084  $queryBuilder->expr()->eq('ISEC.phash', $queryBuilder->quoteIdentifier('IR.phash'))
1085  );
1086  switch ($this->sortOrder) {
1087  case 'rank_flag':
1088  // This gives priority to word-position (max-value) so that words in title, keywords, description counts more than in content.
1089  // The ordering is refined with the frequency sum as well.
1090  $queryBuilder
1091  ->addSelectLiteral(
1092  $queryBuilder->expr()->max('IR.flags', 'order_val1'),
1093  $queryBuilder->expr()->sum('IR.freq', 'order_val2')
1094  )
1095  ->orderBy('order_val1', $this->‪getDescendingSortOrderFlag())
1096  ->addOrderBy('order_val2', $this->‪getDescendingSortOrderFlag());
1097  break;
1098  case 'rank_first':
1099  // Results in average position of search words on page.
1100  // Must be inversely sorted (low numbers are closer to top)
1101  $queryBuilder
1102  ->addSelectLiteral($queryBuilder->expr()->avg('IR.first', 'order_val'))
1103  ->orderBy('order_val', $this->‪getDescendingSortOrderFlag(true));
1104  break;
1105  case 'rank_count':
1106  // Number of words found
1107  $queryBuilder
1108  ->addSelectLiteral($queryBuilder->expr()->sum('IR.count', 'order_val'))
1109  ->orderBy('order_val', $this->‪getDescendingSortOrderFlag());
1110  break;
1111  default:
1112  // Frequency sum. I'm not sure if this is the best way to do
1113  // it (make a sum...). Or should it be the average?
1114  $queryBuilder
1115  ->addSelectLiteral($queryBuilder->expr()->sum('IR.freq', 'order_val'))
1116  ->orderBy('order_val', $this->‪getDescendingSortOrderFlag());
1117  }
1118 
1119  if (!empty($this->wSelClauses)) {
1120  // So, words are combined in an OR statement
1121  // (no "sentence search" should be done here - may deselect results)
1122  $wordSel = $queryBuilder->expr()->orX();
1123  foreach ($this->wSelClauses as $wSelClause) {
1124  $wordSel->add(‪QueryHelper::stripLogicalOperatorPrefix($wSelClause));
1125  }
1126  $queryBuilder->andWhere($wordSel);
1127  }
1128  } else {
1129  // Otherwise, if sorting are done with the pages table or other fields,
1130  // there is no need for joining with the rel/word tables:
1131  switch ((string)$this->sortOrder) {
1132  case 'title':
1133  $queryBuilder->orderBy('IP.item_title', $this->‪getDescendingSortOrderFlag());
1134  break;
1135  case 'crdate':
1136  $queryBuilder->orderBy('IP.item_crdate', $this->‪getDescendingSortOrderFlag());
1137  break;
1138  case 'mtime':
1139  $queryBuilder->orderBy('IP.item_mtime', $this->‪getDescendingSortOrderFlag());
1140  break;
1141  }
1142  }
1143 
1144  return $queryBuilder->execute();
1145  }
1146 
1155  protected function ‪checkResume($row)
1156  {
1157  // If the record is indexed by an indexing configuration, just show it.
1158  // At least this is needed for external URLs and files.
1159  // For records we might need to extend this - for instance block display if record is access restricted.
1160  if ($row['freeIndexUid']) {
1161  return true;
1162  }
1163  // Evaluate regularly indexed pages based on item_type:
1164  // External media:
1165  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('index_grlist');
1166  if ($row['item_type']) {
1167  // For external media we will check the access of the parent page on which the media was linked from.
1168  // "phash_t3" is the phash of the parent TYPO3 page row which initiated the indexing of the documents
1169  // in this section. So, selecting for the grlist records belonging to the parent phash-row where the
1170  // current users gr_list exists will help us to know. If this is NOT found, there is still a theoretical
1171  // possibility that another user accessible page would display a link, so maybe the resume of such a
1172  // document here may be unjustified hidden. But better safe than sorry.
1173  if (!$this->‪isTableUsed('index_grlist')) {
1174  return false;
1175  }
1176 
1177  return (bool)$connection->count(
1178  'phash',
1179  'index_grlist',
1180  [
1181  'phash' => (int)$row['phash_t3'],
1182  'gr_list' => $this->frontendUserGroupList
1183  ]
1184  );
1185  }
1186  // Ordinary TYPO3 pages:
1187  if ((string)$row['gr_list'] !== (string)$this->frontendUserGroupList) {
1188  // Selecting for the grlist records belonging to the phash-row where the current users gr_list exists.
1189  // If it is found it is proof that this user has direct access to the phash-rows content although
1190  // he did not himself initiate the indexing...
1191  if (!$this->‪isTableUsed('index_grlist')) {
1192  return false;
1193  }
1194 
1195  return (bool)$connection->count(
1196  'phash',
1197  'index_grlist',
1198  [
1199  'phash' => (int)$row['phash'],
1200  'gr_list' => $this->frontendUserGroupList
1201  ]
1202  );
1203  }
1204  return true;
1205  }
1206 
1214  protected function ‪getDescendingSortOrderFlag($inverse = false)
1215  {
1217  if ($inverse) {
1218  $desc = !$desc;
1219  }
1220  return !$desc ? ' DESC' : '';
1221  }
1222 
1229  protected function ‪multiplePagesType($itemType)
1230  {
1232  $fileContentParser = $this->externalParsers[$itemType];
1233  return is_object($fileContentParser) && $fileContentParser->isMultiplePageExtension($itemType);
1234  }
1235 
1245  protected function ‪md5inthash($str)
1246  {
1248  }
1249 
1258  protected function ‪isTableUsed($table_list)
1259  {
1261  }
1262 
1269  public function ‪hookRequest($functionName)
1270  {
1271  // Hook: menuConfig_preProcessModMenu
1272  if (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]) {
1273  $hookObj = GeneralUtility::makeInstance(‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]);
1274  if (method_exists($hookObj, $functionName)) {
1275  $hookObj->pObj = $this;
1276  return $hookObj;
1277  }
1278  }
1279  return null;
1280  }
1281 
1288  public function ‪getSearchType()
1289  {
1290  return (int)‪$this->searchType;
1291  }
1292 
1298  public function ‪getSearchRootPageIdList()
1299  {
1300  return GeneralUtility::intExplode(',', $this->searchRootPageIdList);
1301  }
1302 
1309  public function ‪getJoinPagesForQuery()
1310  {
1312  }
1313 
1317  protected function ‪getTypoScriptFrontendController()
1318  {
1319  return ‪$GLOBALS['TSFE'];
1320  }
1321 
1325  protected function ‪getTimeTracker()
1326  {
1327  return GeneralUtility::makeInstance(TimeTracker::class);
1328  }
1329 }
‪TYPO3\CMS\IndexedSearch\Utility\IndexedSearchUtility\md5inthash
‪static int md5inthash($stringToHash)
Definition: IndexedSearchUtility.php:45
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\searchDistinct
‪Statement searchDistinct($sWord)
Definition: IndexSearchRepository.php:706
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$sortOrder
‪string $sortOrder
Definition: IndexSearchRepository.php:87
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$languageUid
‪int $languageUid
Definition: IndexSearchRepository.php:73
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$numberOfResults
‪int $numberOfResults
Definition: IndexSearchRepository.php:108
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\getResultRows_SQLpointerMysqlFulltext
‪bool mysqli_result object getResultRows_SQLpointerMysqlFulltext($searchWordsArray, $freeIndexUid=-1)
Definition: IndexSearchRepository.php:317
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\getJoinPagesForQuery
‪bool getJoinPagesForQuery()
Definition: IndexSearchRepository.php:1293
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\getTimeTracker
‪TimeTracker getTimeTracker()
Definition: IndexSearchRepository.php:1309
‪TYPO3\CMS\Core\Configuration\ExtensionConfiguration
Definition: ExtensionConfiguration.php:42
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\md5inthash
‪int md5inthash($str)
Definition: IndexSearchRepository.php:1229
‪TYPO3\CMS\IndexedSearch\Domain\Repository
Definition: AdministrationRepository.php:2
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository
Definition: IndexSearchRepository.php:35
‪TYPO3
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\getSearchRootPageIdList
‪int[] getSearchRootPageIdList()
Definition: IndexSearchRepository.php:1282
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\mediaTypeWhere
‪string mediaTypeWhere()
Definition: IndexSearchRepository.php:829
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\getTypoScriptFrontendController
‪TYPO3 CMS Frontend Controller TypoScriptFrontendController getTypoScriptFrontendController()
Definition: IndexSearchRepository.php:1301
‪TYPO3\CMS\IndexedSearch\Utility\IndexedSearchUtility\isTableUsed
‪static bool isTableUsed($tableName)
Definition: IndexedSearchUtility.php:32
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$resultpagePointer
‪int $resultpagePointer
Definition: IndexSearchRepository.php:101
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\getDescendingSortOrderFlag
‪string getDescendingSortOrderFlag($inverse=false)
Definition: IndexSearchRepository.php:1198
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\searchWord
‪Statement searchWord($sWord, $wildcard)
Definition: IndexSearchRepository.php:688
‪TYPO3\CMS\IndexedSearch\Utility\LikeWildcard\LEFT
‪const LEFT
Definition: LikeWildcard.php:32
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\getResultRows_SQLpointer
‪Statement getResultRows_SQLpointer($searchWords, $freeIndexUid=-1)
Definition: IndexSearchRepository.php:292
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\initialize
‪initialize($settings, $searchData, $externalParsers, $searchRootPageIdList)
Definition: IndexSearchRepository.php:160
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$mediaType
‪int $mediaType
Definition: IndexSearchRepository.php:80
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:49
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$displayForbiddenRecords
‪bool $displayForbiddenRecords
Definition: IndexSearchRepository.php:150
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\execFinalQuery
‪Statement execFinalQuery($list, $freeIndexUid=-1)
Definition: IndexSearchRepository.php:960
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\doSearch
‪bool array doSearch($searchWords, $freeIndexUid=-1)
Definition: IndexSearchRepository.php:196
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\hookRequest
‪object null hookRequest($functionName)
Definition: IndexSearchRepository.php:1253
‪TYPO3\CMS\IndexedSearch\Utility
Definition: DoubleMetaPhoneUtility.php:2
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\getSearchType
‪int getSearchType()
Definition: IndexSearchRepository.php:1272
‪TYPO3\CMS\Core\Type\Enumeration\cast
‪static static cast($value)
Definition: Enumeration.php:182
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$wSelClauses
‪array $wSelClauses
Definition: IndexSearchRepository.php:129
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:30
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$descendingSortOrderFlag
‪bool $descendingSortOrderFlag
Definition: IndexSearchRepository.php:94
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\multiplePagesType
‪bool multiplePagesType($itemType)
Definition: IndexSearchRepository.php:1213
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\searchMetaphone
‪Statement searchMetaphone($sWord)
Definition: IndexSearchRepository.php:751
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\isTableUsed
‪bool isTableUsed($table_list)
Definition: IndexSearchRepository.php:1242
‪TYPO3\CMS\Core\TimeTracker\TimeTracker\pull
‪pull($content='')
Definition: TimeTracker.php:173
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$searchRootPageIdList
‪string $searchRootPageIdList
Definition: IndexSearchRepository.php:116
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\sectionTableWhere
‪string sectionTableWhere()
Definition: IndexSearchRepository.php:766
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$sections
‪string $sections
Definition: IndexSearchRepository.php:59
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$useExactCount
‪bool $useExactCount
Definition: IndexSearchRepository.php:141
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$externalParsers
‪array $externalParsers
Definition: IndexSearchRepository.php:46
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$searchType
‪string $searchType
Definition: IndexSearchRepository.php:66
‪TYPO3\CMS\IndexedSearch\Utility\LikeWildcard\BOTH
‪const BOTH
Definition: LikeWildcard.php:38
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$joinPagesForQuery
‪bool $joinPagesForQuery
Definition: IndexSearchRepository.php:123
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$indexerObj
‪Indexer $indexerObj
Definition: IndexSearchRepository.php:40
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\freeIndexUidWhere
‪string freeIndexUidWhere($freeIndexUid)
Definition: IndexSearchRepository.php:880
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\execPHashListQuery
‪Statement execPHashListQuery($wordSel, $additionalWhereClause='')
Definition: IndexSearchRepository.php:662
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:31
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\searchSentence
‪Statement searchSentence($sWord)
Definition: IndexSearchRepository.php:722
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\execFinalQuery_fulltext
‪Statement execFinalQuery_fulltext($searchData, $freeIndexUid=-1)
Definition: IndexSearchRepository.php:434
‪TYPO3\CMS\Core\Database\Query\QueryHelper\stripLogicalOperatorPrefix
‪static string stripLogicalOperatorPrefix(string $constraint)
Definition: QueryHelper.php:163
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:21
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\checkResume
‪bool checkResume($row)
Definition: IndexSearchRepository.php:1139
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\IndexedSearch\Indexer
Definition: Indexer.php:38
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\IndexedSearch\Indexer\metaphone
‪mixed metaphone($word, $returnRawMetaphoneValue=false)
Definition: Indexer.php:1410
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer
Definition: FrontendRestrictionContainer.php:29
‪TYPO3\CMS\Core\TimeTracker\TimeTracker
Definition: TimeTracker.php:27
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\getSearchString
‪array getSearchString($searchWordArray)
Definition: IndexSearchRepository.php:350
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\languageWhere
‪string languageWhere()
Definition: IndexSearchRepository.php:860
‪TYPO3\CMS\IndexedSearch\Utility\LikeWildcard\RIGHT
‪const RIGHT
Definition: LikeWildcard.php:35
‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository\$frontendUserGroupList
‪string $frontendUserGroupList
Definition: IndexSearchRepository.php:52
‪TYPO3\CMS\Core\TimeTracker\TimeTracker\push
‪push($tslabel, $value='')
Definition: TimeTracker.php:147