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