‪TYPO3CMS  9.5
SearchController.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 
37 
46 {
52  protected ‪$sword = '';
53 
57  protected ‪$searchWords = [];
58 
62  protected ‪$searchData;
63 
73  protected ‪$searchRootPageIdList = 0;
74 
78  protected ‪$defaultResultNumber = 10;
79 
84 
90  protected ‪$searchRepository;
91 
97  protected ‪$lexerObj;
98 
103  protected ‪$externalParsers = [];
104 
110  protected ‪$firstRow = [];
111 
117  protected ‪$domainRecords = [];
118 
125 
131  protected ‪$resultSections = [];
132 
138  protected ‪$pathCache = [];
139 
145  protected ‪$iconFileNameCache = [];
146 
152  protected ‪$indexerConfig = [];
153 
159  protected ‪$enableMetaphoneSearch = false;
160 
164  protected ‪$typoScriptService;
165 
170  {
171  $this->typoScriptService = ‪$typoScriptService;
172  }
173 
180  public function ‪initialize(‪$searchData = [])
181  {
182  if (!is_array(‪$searchData)) {
183  ‪$searchData = [];
184  }
185 
186  // check if TypoScript is loaded
187  if (!isset($this->settings['results'])) {
188  $this->‪redirect('noTypoScript');
189  }
190 
191  // Sets availableResultsNumbers - has to be called before request settings are read to avoid DoS attack
192  $this->availableResultsNumbers = array_filter(GeneralUtility::intExplode(',', $this->settings['blind']['numberOfResults']));
193 
194  // Sets default result number if at least one availableResultsNumbers exists
195  if (isset($this->availableResultsNumbers[0])) {
196  $this->defaultResultNumber = $this->availableResultsNumbers[0];
197  }
198 
199  $this->‪loadSettings();
200 
201  // setting default values
202  if (is_array($this->settings['defaultOptions'])) {
203  ‪$searchData = array_merge($this->settings['defaultOptions'], ‪$searchData);
204  }
205  // if "languageUid" was set to "current", take the current site language
206  if ((‪$searchData['languageUid'] ?? '') === 'current') {
207  ‪$searchData['languageUid'] = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('language', 'id', 0);
208  }
209 
210  // Indexer configuration from Extension Manager interface:
211  $this->indexerConfig = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('indexed_search');
212  $this->enableMetaphoneSearch = (bool)$this->indexerConfig['enableMetaphoneSearch'];
214  // If "_sections" is set, this value overrides any existing value.
215  if (‪$searchData['_sections']) {
216  ‪$searchData['sections'] = ‪$searchData['_sections'];
217  }
218  // If "_sections" is set, this value overrides any existing value.
219  if (‪$searchData['_freeIndexUid'] !== '' && ‪$searchData['_freeIndexUid'] !== '_') {
220  ‪$searchData['freeIndexUid'] = ‪$searchData['_freeIndexUid'];
221  }
222  ‪$searchData['numberOfResults'] = $this->‪getNumberOfResults(‪$searchData['numberOfResults']);
223  // This gets the search-words into the $searchWordArray
224  $this->‪setSword(‪$searchData['sword']);
225  // Add previous search words to current
226  if (‪$searchData['sword_prev_include'] && ‪$searchData['sword_prev']) {
227  $this->‪setSword(trim(‪$searchData['sword_prev']) . ' ' . $this->‪getSword());
228  }
229  $this->searchWords = $this->‪getSearchWords(‪$searchData['defaultOperand']);
230  // This is the id of the site root.
231  // This value may be a commalist of integer (prepared for this)
232  $this->searchRootPageIdList = (int)‪$GLOBALS['TSFE']->config['rootLine'][0]['uid'];
233  // Setting the list of root PIDs for the search. Notice, these page IDs MUST
234  // have a TypoScript template with root flag on them! Basically this list is used
235  // to select on the "rl0" field and page ids are registered as "rl0" only if
236  // a TypoScript template record with root flag is there.
237  // This happens AFTER the use of $this->searchRootPageIdList above because
238  // the above will then fetch the menu for the CURRENT site - regardless
239  // of this kind of searching here. Thus a general search will lookup in
240  // the WHOLE database while a specific section search will take the current sections.
241  if ($this->settings['rootPidList']) {
242  $this->searchRootPageIdList = implode(',', GeneralUtility::intExplode(',', $this->settings['rootPidList']));
243  }
244  $this->searchRepository = GeneralUtility::makeInstance(\‪TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository::class);
245  $this->searchRepository->initialize($this->settings, ‪$searchData, $this->externalParsers, $this->searchRootPageIdList);
246  $this->searchData = ‪$searchData;
247  // Calling hook for modification of initialized content
248  if ($hookObj = $this->‪hookRequest('initialize_postProc')) {
249  $hookObj->initialize_postProc();
250  }
251  return ‪$searchData;
252  }
253 
260  public function ‪searchAction($search = [])
261  {
262  ‪$searchData = $this->‪initialize($search);
263  // Find free index uid:
264  $freeIndexUid = ‪$searchData['freeIndexUid'];
265  if ($freeIndexUid == -2) {
266  $freeIndexUid = $this->settings['defaultFreeIndexUidList'];
267  } elseif (!isset(‪$searchData['freeIndexUid'])) {
268  // index configuration is disabled
269  $freeIndexUid = -1;
270  }
271 
272  if (!empty(‪$searchData['extendedSearch'])) {
273  $this->view->assignMultiple($this->‪processExtendedSearchParameters());
274  }
275 
276  $indexCfgs = GeneralUtility::intExplode(',', $freeIndexUid);
277  $resultsets = [];
278  foreach ($indexCfgs as $freeIndexUid) {
279  // Get result rows
280  $tstamp1 = GeneralUtility::milliseconds();
281  if ($hookObj = $this->‪hookRequest('getResultRows')) {
282  $resultData = $hookObj->getResultRows($this->searchWords, $freeIndexUid);
283  } else {
284  $resultData = $this->searchRepository->doSearch($this->searchWords, $freeIndexUid);
285  }
286  // Display search results
287  $tstamp2 = GeneralUtility::milliseconds();
288  if ($hookObj = $this->‪hookRequest('getDisplayResults')) {
289  $resultsets[$freeIndexUid] = $hookObj->getDisplayResults($this->searchWords, $resultData, $freeIndexUid);
290  } else {
291  $resultsets[$freeIndexUid] = $this->‪getDisplayResults($this->searchWords, $resultData, $freeIndexUid);
292  }
293  $tstamp3 = GeneralUtility::milliseconds();
294  // Create header if we are searching more than one indexing configuration
295  if (count($indexCfgs) > 1) {
296  if ($freeIndexUid > 0) {
297  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
298  ->getQueryBuilderForTable('index_config');
299  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
300  $indexCfgRec = $queryBuilder
301  ->select('*')
302  ->from('index_config')
303  ->where(
304  $queryBuilder->expr()->eq(
305  'uid',
306  $queryBuilder->createNamedParameter($freeIndexUid, \PDO::PARAM_INT)
307  )
308  )
309  ->execute()
310  ->fetch();
311  $categoryTitle = $indexCfgRec['title'];
312  } else {
313  $categoryTitle = ‪LocalizationUtility::translate('indexingConfigurationHeader.' . $freeIndexUid, 'IndexedSearch');
314  }
315  $resultsets[$freeIndexUid]['categoryTitle'] = $categoryTitle;
316  }
317  // Write search statistics
318  $this->‪writeSearchStat(‪$searchData, $this->searchWords, $resultData['count'], [$tstamp1, $tstamp2, $tstamp3]);
319  }
320  $this->view->assign('resultsets', $resultsets);
321  $this->view->assign('searchParams', ‪$searchData);
322  $this->view->assign('searchWords', $this->searchWords);
323  }
324 
325  /****************************************
326  * functions to make the result rows and result sets
327  * ready for the output
328  ***************************************/
337  protected function ‪getDisplayResults(‪$searchWords, $resultData, $freeIndexUid = -1)
338  {
339  $result = [
340  'count' => $resultData['count'],
341  'searchWords' => ‪$searchWords
342  ];
343  // Perform display of result rows array
344  if ($resultData) {
345  // Set first selected row (for calculation of ranking later)
346  $this->firstRow = $resultData['firstRow'];
347  // Result display here
348  $result['rows'] = $this->‪compileResultRows($resultData['resultRows'], $freeIndexUid);
349  $result['affectedSections'] = ‪$this->resultSections;
350  // Browsing box
351  if ($resultData['count']) {
352  // could we get this in the view?
353  if ($this->searchData['group'] === 'sections' && $freeIndexUid <= 0) {
354  $resultSectionsCount = count($this->resultSections);
355  $result['sectionText'] = sprintf(‪LocalizationUtility::translate('result.' . ($resultSectionsCount > 1 ? 'inNsections' : 'inNsection'), 'IndexedSearch'), $resultSectionsCount);
356  }
357  }
358  }
359  // Print a message telling which words in which sections we searched for
360  if (strpos($this->searchData['sections'], 'rl') === 0) {
361  $result['searchedInSectionInfo'] = ‪LocalizationUtility::translate('result.inSection', 'IndexedSearch') . ' "' . $this->‪getPathFromPageId(substr($this->searchData['sections'], 4)) . '"';
362  }
363 
364  if ($hookObj = $this->‪hookRequest('getDisplayResults_postProc')) {
365  $result = $hookObj->getDisplayResults_postProc($result);
366  }
367 
368  return $result;
369  }
370 
379  protected function ‪compileResultRows($resultRows, $freeIndexUid = -1)
380  {
381  $finalResultRows = [];
382  // Transfer result rows to new variable,
383  // performing some mapping of sub-results etc.
384  $newResultRows = [];
385  foreach ($resultRows as $row) {
386  $id = md5($row['phash_grouping']);
387  if (is_array($newResultRows[$id])) {
388  // swapping:
389  if (!$newResultRows[$id]['show_resume'] && $row['show_resume']) {
390  // Remove old
391  $subrows = $newResultRows[$id]['_sub'];
392  unset($newResultRows[$id]['_sub']);
393  $subrows[] = $newResultRows[$id];
394  // Insert new:
395  $newResultRows[$id] = $row;
396  $newResultRows[$id]['_sub'] = $subrows;
397  } else {
398  $newResultRows[$id]['_sub'][] = $row;
399  }
400  } else {
401  $newResultRows[$id] = $row;
402  }
403  }
404  $resultRows = $newResultRows;
405  $this->resultSections = [];
406  if ($freeIndexUid <= 0 && $this->searchData['group'] === 'sections') {
407  $rl2flag = strpos($this->searchData['sections'], 'rl') === 0;
408  $sections = [];
409  foreach ($resultRows as $row) {
410  $id = $row['rl0'] . '-' . $row['rl1'] . ($rl2flag ? '-' . $row['rl2'] : '');
411  $sections[$id][] = $row;
412  }
413  $this->resultSections = [];
414  foreach ($sections as $id => $resultRows) {
415  $rlParts = explode('-', $id);
416  if ($rlParts[2]) {
417  $theId = $rlParts[2];
418  $theRLid = 'rl2_' . $rlParts[2];
419  } elseif ($rlParts[1]) {
420  $theId = $rlParts[1];
421  $theRLid = 'rl1_' . $rlParts[1];
422  } else {
423  $theId = $rlParts[0];
424  $theRLid = '0';
425  }
426  $sectionName = $this->‪getPathFromPageId($theId);
427  $sectionName = ltrim($sectionName, '/');
428  if (!trim($sectionName)) {
429  $sectionTitleLinked = ‪LocalizationUtility::translate('result.unnamedSection', 'IndexedSearch') . ':';
430  } else {
431  $onclick = 'document.forms[\'tx_indexedsearch\'][\'tx_indexedsearch_pi2[search][_sections]\'].value=' . GeneralUtility::quoteJSvalue($theRLid) . ';document.forms[\'tx_indexedsearch\'].submit();return false;';
432  $sectionTitleLinked = '<a href="#" onclick="' . htmlspecialchars($onclick) . '">' . $sectionName . ':</a>';
433  }
434  $resultRowsCount = count($resultRows);
435  $this->resultSections[$id] = [$sectionName, $resultRowsCount];
436  // Add section header
437  $finalResultRows[] = [
438  'isSectionHeader' => true,
439  'numResultRows' => $resultRowsCount,
440  'sectionId' => $id,
441  'sectionTitle' => $sectionTitleLinked
442  ];
443  // Render result rows
444  foreach ($resultRows as $row) {
445  $finalResultRows[] = $this->‪compileSingleResultRow($row);
446  }
447  }
448  } else {
449  // flat mode or no sections at all
450  foreach ($resultRows as $row) {
451  $finalResultRows[] = $this->‪compileSingleResultRow($row);
452  }
453  }
454  return $finalResultRows;
455  }
456 
464  protected function ‪compileSingleResultRow($row, $headerOnly = 0)
465  {
466  $specRowConf = $this->‪getSpecialConfigurationForResultRow($row);
467  $resultData = $row;
468  $resultData['headerOnly'] = $headerOnly;
469  $resultData['CSSsuffix'] = $specRowConf['CSSsuffix'] ? '-' . $specRowConf['CSSsuffix'] : '';
470  if ($this->‪multiplePagesType($row['item_type'])) {
471  $dat = unserialize($row['cHashParams']);
472  $pp = explode('-', $dat['key']);
473  if ($pp[0] != $pp[1]) {
474  $resultData['titleaddition'] = ', ' . ‪LocalizationUtility::translate('result.page', 'IndexedSearch') . ' ' . $dat['key'];
475  } else {
476  $resultData['titleaddition'] = ', ' . ‪LocalizationUtility::translate('result.pages', 'IndexedSearch') . ' ' . $pp[0];
477  }
478  }
479  $title = $resultData['item_title'] . $resultData['titleaddition'];
480  $title = GeneralUtility::fixed_lgd_cs($title, $this->settings['results.']['titleCropAfter'], $this->settings['results.']['titleCropSignifier']);
481  // If external media, link to the media-file instead.
482  if ($row['item_type']) {
483  if ($row['show_resume']) {
484  // Can link directly.
485  $targetAttribute = '';
486  if (‪$GLOBALS['TSFE']->config['config']['fileTarget']) {
487  $targetAttribute = ' target="' . htmlspecialchars(‪$GLOBALS['TSFE']->config['config']['fileTarget']) . '"';
488  }
489  $title = '<a href="' . htmlspecialchars($row['data_filename']) . '"' . $targetAttribute . '>' . htmlspecialchars($title) . '</a>';
490  } else {
491  // Suspicious, so linking to page instead...
492  $copiedRow = $row;
493  unset($copiedRow['cHashParams']);
494  $title = $this->‪linkPageATagWrap(
495  $title,
496  $this->‪linkPage($row['page_id'], $copiedRow)
497  );
498  }
499  } else {
500  // Else the page:
501  // Prepare search words for markup in content:
502  $markUpSwParams = [];
503  if ($this->settings['forwardSearchWordsInResultLink']['_typoScriptNodeValue']) {
504  if ($this->settings['forwardSearchWordsInResultLink']['no_cache']) {
505  $markUpSwParams = ['no_cache' => 1];
506  }
507  foreach ($this->searchWords as $d) {
508  $markUpSwParams['sword_list'][] = $d['sword'];
509  }
510  }
511  $title = $this->‪linkPageATagWrap(
512  $title,
513  $this->‪linkPage($row['data_page_id'], $row, $markUpSwParams)
514  );
515  }
516  $resultData['title'] = $title;
517  $resultData['icon'] = $this->‪makeItemTypeIcon($row['item_type'], '', $specRowConf);
518  $resultData['rating'] = $this->‪makeRating($row);
519  $resultData['description'] = $this->‪makeDescription(
520  $row,
521  (bool)!($this->searchData['extResume'] && !$headerOnly),
522  $this->settings['results.']['summaryCropAfter']
523  );
524  $resultData['language'] = $this->‪makeLanguageIndication($row);
525  $resultData['size'] = GeneralUtility::formatSize($row['item_size']);
526  $resultData['created'] = $row['item_crdate'];
527  $resultData['modified'] = $row['item_mtime'];
528  $pI = parse_url($row['data_filename']);
529  if ($pI['scheme']) {
530  $targetAttribute = '';
531  if (‪$GLOBALS['TSFE']->config['config']['fileTarget']) {
532  $targetAttribute = ' target="' . htmlspecialchars(‪$GLOBALS['TSFE']->config['config']['fileTarget']) . '"';
533  }
534  $resultData['pathTitle'] = $row['data_filename'];
535  $resultData['pathUri'] = $row['data_filename'];
536  $resultData['path'] = '<a href="' . htmlspecialchars($row['data_filename']) . '"' . $targetAttribute . '>' . htmlspecialchars($row['data_filename']) . '</a>';
537  } else {
538  $pathId = $row['data_page_id'] ?: $row['page_id'];
539  $pathMP = $row['data_page_id'] ? $row['data_page_mp'] : '';
540  $pathStr = $this->‪getPathFromPageId($pathId, $pathMP);
541  $pathLinkData = $this->‪linkPage(
542  $pathId,
543  [
544  'cHashParams' => $row['cHashParams'],
545  'data_page_type' => $row['data_page_type'],
546  'data_page_mp' => $pathMP,
547  'sys_language_uid' => $row['sys_language_uid'],
548  'static_page_arguments' => $row['static_page_arguments']
549  ]
550  );
551 
552  $resultData['pathTitle'] = $pathStr;
553  $resultData['pathUri'] = $pathLinkData['uri'];
554  $resultData['path'] = $this->‪linkPageATagWrap($pathStr, $pathLinkData);
555 
556  // check if the access is restricted
557  if (is_array($this->requiredFrontendUsergroups[$pathId]) && !empty($this->requiredFrontendUsergroups[$pathId])) {
558  $lockedIcon = GeneralUtility::getFileAbsFileName('EXT:indexed_search/Resources/Public/Icons/FileTypes/locked.gif');
559  $lockedIcon = ‪PathUtility::getAbsoluteWebPath($lockedIcon);
560  $resultData['access'] = '<img src="' . htmlspecialchars($lockedIcon) . '"'
561  . ' width="12" height="15" vspace="5" title="'
562  . sprintf(‪LocalizationUtility::translate('result.memberGroups', 'IndexedSearch'), implode(',', array_unique($this->requiredFrontendUsergroups[$pathId])))
563  . '" alt="" />';
564  }
565  }
566  // If there are subrows (eg. subpages in a PDF-file or if a duplicate page
567  // is selected due to user-login (phash_grouping))
568  if (is_array($row['_sub'])) {
569  $resultData['subresults'] = [];
570  if ($this->‪multiplePagesType($row['item_type'])) {
571  $resultData['subresults']['header'] = ‪LocalizationUtility::translate('result.otherMatching', 'IndexedSearch');
572  foreach ($row['_sub'] as $subRow) {
573  $resultData['subresults']['items'][] = $this->‪compileSingleResultRow($subRow, 1);
574  }
575  } else {
576  $resultData['subresults']['header'] = ‪LocalizationUtility::translate('result.otherMatching', 'IndexedSearch');
577  $resultData['subresults']['info'] = ‪LocalizationUtility::translate('result.otherPageAsWell', 'IndexedSearch');
578  }
579  }
580  return $resultData;
581  }
582 
590  protected function ‪getSpecialConfigurationForResultRow($row)
591  {
592  $pathId = $row['data_page_id'] ?: $row['page_id'];
593  $pathMP = $row['data_page_id'] ? $row['data_page_mp'] : '';
594  $specConf = $this->settings['specialConfiguration']['0'];
595  try {
596  $rl = GeneralUtility::makeInstance(RootlineUtility::class, $pathId, $pathMP)->get();
597  foreach ($rl as $dat) {
598  if (is_array($this->settings['specialConfiguration'][$dat['uid']])) {
599  $specConf = $this->settings['specialConfiguration'][$dat['uid']];
600  $specConf['_pid'] = $dat['uid'];
601  break;
602  }
603  }
604  } catch (RootLineException $e) {
605  // do nothing
606  }
607  return $specConf;
608  }
609 
617  protected function ‪makeRating($row)
618  {
619  switch ((string)$this->searchData['sortOrder']) {
620  case 'rank_count':
621  return $row['order_val'] . ' ' . ‪LocalizationUtility::translate('result.ratingMatches', 'IndexedSearch');
622  case 'rank_first':
623  return ceil(‪MathUtility::forceIntegerInRange(255 - $row['order_val'], 1, 255) / 255 * 100) . '%';
624  case 'rank_flag':
625  if ($this->firstRow['order_val2']) {
626  // (3 MSB bit, 224 is highest value of order_val1 currently)
627  $base = $row['order_val1'] * 256;
628  // 15-3 MSB = 12
629  $freqNumber = $row['order_val2'] / $this->firstRow['order_val2'] * pow(2, 12);
630  $total = ‪MathUtility::forceIntegerInRange($base + $freqNumber, 0, 32767);
631  return ceil(log($total) / log(32767) * 100) . '%';
632  }
633  break;
634  case 'rank_freq':
635  $max = 10000;
636  $total = ‪MathUtility::forceIntegerInRange($row['order_val'], 0, $max);
637  return ceil(log($total) / log($max) * 100) . '%';
638  case 'crdate':
639  return ‪$GLOBALS['TSFE']->cObj->calcAge(‪$GLOBALS['EXEC_TIME'] - $row['item_crdate'], 0);
640  case 'mtime':
641  return ‪$GLOBALS['TSFE']->cObj->calcAge(‪$GLOBALS['EXEC_TIME'] - $row['item_mtime'], 0);
642  default:
643  return ' ';
644  }
645  }
646 
653  protected function ‪makeLanguageIndication($row)
654  {
655  ‪$output = '&nbsp;';
656  // If search result is a TYPO3 page:
657  if ((string)$row['item_type'] === '0') {
658  // If TypoScript is used to render the flag:
659  if (is_array($this->settings['flagRendering'])) {
661  $cObj = GeneralUtility::makeInstance(\‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class);
662  $cObj->setCurrentVal($row['sys_language_uid']);
663  $typoScriptArray = $this->typoScriptService->convertPlainArrayToTypoScriptArray($this->settings['flagRendering']);
664  ‪$output = $cObj->cObjGetSingle($this->settings['flagRendering']['_typoScriptNodeValue'], $typoScriptArray);
665  }
666  }
667  return ‪$output;
668  }
669 
678  public function ‪makeItemTypeIcon($imageType, $alt, $specRowConf)
679  {
680  // Build compound key if item type is 0, iconRendering is not used
681  // and specialConfiguration.[pid].pageIcon was set in TS
682  if ($imageType === '0' && $specRowConf['_pid'] && is_array($specRowConf['pageIcon']) && !is_array($this->settings['iconRendering'])) {
683  $imageType .= ':' . $specRowConf['_pid'];
684  }
685  if (!isset($this->iconFileNameCache[$imageType])) {
686  $this->iconFileNameCache[$imageType] = '';
687  // If TypoScript is used to render the icon:
688  if (is_array($this->settings['iconRendering'])) {
690  $cObj = GeneralUtility::makeInstance(\‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class);
691  $cObj->setCurrentVal($imageType);
692  $typoScriptArray = $this->typoScriptService->convertPlainArrayToTypoScriptArray($this->settings['iconRendering']);
693  $this->iconFileNameCache[$imageType] = $cObj->cObjGetSingle($this->settings['iconRendering']['_typoScriptNodeValue'], $typoScriptArray);
694  } else {
695  // Default creation / finding of icon:
696  $icon = '';
697  if ($imageType === '0' || strpos($imageType, '0:') === 0) {
698  if (is_array($specRowConf['pageIcon'])) {
699  $this->iconFileNameCache[$imageType] = ‪$GLOBALS['TSFE']->cObj->cObjGetSingle('IMAGE', $specRowConf['pageIcon']);
700  } else {
701  $icon = 'EXT:indexed_search/Resources/Public/Icons/FileTypes/pages.gif';
702  }
703  } elseif ($this->externalParsers[$imageType]) {
704  $icon = $this->externalParsers[$imageType]->getIcon($imageType);
705  }
706  if ($icon) {
707  $fullPath = GeneralUtility::getFileAbsFileName($icon);
708  if ($fullPath) {
709  $imageInfo = GeneralUtility::makeInstance(ImageInfo::class, $fullPath);
710  $iconPath = ‪PathUtility::stripPathSitePrefix($fullPath);
711  $this->iconFileNameCache[$imageType] = $imageInfo->getWidth()
712  ? '<img src="' . $iconPath
713  . '" width="' . $imageInfo->getWidth()
714  . '" height="' . $imageInfo->getHeight()
715  . '" title="' . htmlspecialchars($alt) . '" alt="" />'
716  : '';
717  }
718  }
719  }
720  }
721  return $this->iconFileNameCache[$imageType];
722  }
723 
733  protected function ‪makeDescription($row, $noMarkup = false, $length = 180)
734  {
735  if ($row['show_resume']) {
736  if (!$noMarkup) {
737  $markedSW = '';
738  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_fulltext');
739  $ftdrow = $queryBuilder
740  ->select('*')
741  ->from('index_fulltext')
742  ->where(
743  $queryBuilder->expr()->eq(
744  'phash',
745  $queryBuilder->createNamedParameter($row['phash'], \PDO::PARAM_INT)
746  )
747  )
748  ->execute()
749  ->fetch();
750  if ($ftdrow !== false) {
751  // Cut HTTP references after some length
752  $content = preg_replace('/(http:\\/\\/[^ ]{' . $this->settings['results.']['hrefInSummaryCropAfter'] . '})([^ ]+)/i', '$1...', $ftdrow['fulltextdata']);
753  $markedSW = $this->‪markupSWpartsOfString($content);
754  }
755  }
756  if (!trim($markedSW)) {
757  $outputStr = GeneralUtility::fixed_lgd_cs($row['item_description'], $length, $this->settings['results.']['summaryCropSignifier']);
758  $outputStr = htmlspecialchars($outputStr);
759  }
760  ‪$output = $outputStr ?: $markedSW;
761  } else {
762  ‪$output = '<span class="noResume">' . ‪LocalizationUtility::translate('result.noResume', 'IndexedSearch') . '</span>';
763  }
764  return ‪$output;
765  }
766 
773  protected function ‪markupSWpartsOfString($str)
774  {
775  $htmlParser = GeneralUtility::makeInstance(HtmlParser::class);
776  // Init:
777  $str = str_replace('&nbsp;', ' ', $htmlParser->bidir_htmlspecialchars($str, -1));
778  $str = preg_replace('/\\s\\s+/', ' ', $str);
779  $swForReg = [];
780  // Prepare search words for regex:
781  foreach ($this->searchWords as $d) {
782  $swForReg[] = preg_quote($d['sword'], '/');
783  }
784  $regExString = '(' . implode('|', $swForReg) . ')';
785  // Split and combine:
786  $parts = preg_split('/' . $regExString . '/i', ' ' . $str . ' ', 20000, PREG_SPLIT_DELIM_CAPTURE);
787  // Constants:
788  $summaryMax = $this->settings['results.']['markupSW_summaryMax'];
789  $postPreLgd = $this->settings['results.']['markupSW_postPreLgd'];
790  $postPreLgd_offset = $this->settings['results.']['markupSW_postPreLgd_offset'];
791  $divider = $this->settings['results.']['markupSW_divider'];
792  $occurencies = (count($parts) - 1) / 2;
793  if ($occurencies) {
794  $postPreLgd = ‪MathUtility::forceIntegerInRange($summaryMax / $occurencies, $postPreLgd, $summaryMax / 2);
795  }
796  // Variable:
797  $summaryLgd = 0;
798  ‪$output = [];
799  // Shorten in-between strings:
800  foreach ($parts as $k => $strP) {
801  if ($k % 2 == 0) {
802  // Find length of the summary part:
803  $strLen = mb_strlen($parts[$k], 'utf-8');
804  ‪$output[$k] = $parts[$k];
805  // Possibly shorten string:
806  if (!$k) {
807  // First entry at all (only cropped on the frontside)
808  if ($strLen > $postPreLgd) {
809  ‪$output[$k] = $divider . preg_replace('/^[^[:space:]]+[[:space:]]/', '', GeneralUtility::fixed_lgd_cs($parts[$k], -($postPreLgd - $postPreLgd_offset)));
810  }
811  } elseif ($summaryLgd > $summaryMax || !isset($parts[$k + 1])) {
812  // In case summary length is exceed OR if there are no more entries at all:
813  if ($strLen > $postPreLgd) {
814  ‪$output[$k] = preg_replace('/[[:space:]][^[:space:]]+$/', '', GeneralUtility::fixed_lgd_cs(
815  $parts[$k],
816  $postPreLgd - $postPreLgd_offset
817  )) . $divider;
818  }
819  } else {
820  if ($strLen > $postPreLgd * 2) {
821  ‪$output[$k] = preg_replace('/[[:space:]][^[:space:]]+$/', '', GeneralUtility::fixed_lgd_cs(
822  $parts[$k],
823  $postPreLgd - $postPreLgd_offset
824  )) . $divider . preg_replace('/^[^[:space:]]+[[:space:]]/', '', GeneralUtility::fixed_lgd_cs($parts[$k], -($postPreLgd - $postPreLgd_offset)));
825  }
826  }
827  $summaryLgd += mb_strlen(‪$output[$k], 'utf-8');
828  // Protect output:
829  ‪$output[$k] = htmlspecialchars(‪$output[$k]);
830  // If summary lgd is exceed, break the process:
831  if ($summaryLgd > $summaryMax) {
832  break;
833  }
834  } else {
835  $summaryLgd += mb_strlen($strP, 'utf-8');
836  ‪$output[$k] = '<strong class="tx-indexedsearch-redMarkup">' . htmlspecialchars($parts[$k]) . '</strong>';
837  }
838  }
839  // Return result:
840  return implode('', ‪$output);
841  }
842 
851  protected function ‪writeSearchStat($searchParams, ‪$searchWords, $count, $pt)
852  {
853  $searchWord = $this->‪getSword();
854  if (empty($searchWord) && empty(‪$searchWords)) {
855  return;
856  }
857 
858  $ipAddress = '';
859  try {
860  $ipMask = isset($this->indexerConfig['trackIpInStatistic']) ? (int)$this->indexerConfig['trackIpInStatistic'] : 2;
861  $ipAddress = ‪IpAnonymizationUtility::anonymizeIp(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $ipMask);
862  } catch (\Exception $e) {
863  }
864  $insertFields = [
865  'searchstring' => $searchWord,
866  'searchoptions' => serialize([$searchParams, ‪$searchWords, $pt]),
867  'feuser_id' => (int)‪$GLOBALS['TSFE']->fe_user->user['uid'],
868  // cookie as set or retrieved. If people has cookies disabled this will vary all the time
869  'cookie' => ‪$GLOBALS['TSFE']->fe_user->id,
870  // Remote IP address
871  'IP' => $ipAddress,
872  // Number of hits on the search
873  'hits' => (int)$count,
874  // Time stamp
875  'tstamp' => ‪$GLOBALS['EXEC_TIME']
876  ];
877  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('index_search_stat');
878  $connection->insert(
879  'index_stat_search',
880  $insertFields,
881  ['searchoptions' => ‪Connection::PARAM_LOB]
882  );
883  $newId = $connection->lastInsertId('index_stat_search');
884  if ($newId) {
885  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('index_stat_word');
886  foreach (‪$searchWords as $val) {
887  $insertFields = [
888  'word' => $val['sword'],
889  'index_stat_search_id' => $newId,
890  // Time stamp
891  'tstamp' => ‪$GLOBALS['EXEC_TIME'],
892  // search page id for indexed search stats
893  'pageid' => ‪$GLOBALS['TSFE']->id
894  ];
895  $connection->insert('index_stat_word', $insertFields);
896  }
897  }
898  }
899 
916  protected function ‪getSearchWords($defaultOperator)
917  {
918  // Shorten search-word string to max 200 bytes - shortening the string here is only a run-away feature!
919  ‪$searchWords = mb_substr($this->‪getSword(), 0, 200);
920  // Convert to UTF-8 + conv. entities (was also converted during indexing!)
921  if (‪$GLOBALS['TSFE']->metaCharset && ‪$GLOBALS['TSFE']->metaCharset !== 'utf-8') {
922  ‪$searchWords = mb_convert_encoding(‪$searchWords, 'utf-8', ‪$GLOBALS['TSFE']->metaCharset);
923  ‪$searchWords = html_entity_decode(‪$searchWords);
924  }
925  $sWordArray = false;
926  if ($hookObj = $this->‪hookRequest('getSearchWords')) {
927  $sWordArray = $hookObj->getSearchWords_splitSWords(‪$searchWords, $defaultOperator);
928  } else {
929  // sentence
930  if ($this->searchData['searchType'] == 20) {
931  $sWordArray = [
932  [
933  'sword' => trim(‪$searchWords),
934  'oper' => 'AND'
935  ]
936  ];
937  } else {
938  // case-sensitive. Defines the words, which will be
939  // operators between words
940  $operatorTranslateTable = [
941  ['+', 'AND'],
942  ['|', 'OR'],
943  ['-', 'AND NOT'],
944  // Add operators for various languages
945  // Converts the operators to lowercase
946  [mb_strtolower(‪LocalizationUtility::translate('localizedOperandAnd', 'IndexedSearch'), 'utf-8'), 'AND'],
947  [mb_strtolower(‪LocalizationUtility::translate('localizedOperandOr', 'IndexedSearch'), 'utf-8'), 'OR'],
948  [mb_strtolower(‪LocalizationUtility::translate('localizedOperandNot', 'IndexedSearch'), 'utf-8'), 'AND NOT']
949  ];
950  $swordArray = ‪\TYPO3\CMS\IndexedSearch\Utility\IndexedSearchUtility::getExplodedSearchString(‪$searchWords, $defaultOperator == 1 ? 'OR' : 'AND', $operatorTranslateTable);
951  if (is_array($swordArray)) {
952  $sWordArray = $this->‪procSearchWordsByLexer($swordArray);
953  }
954  }
955  }
956  return $sWordArray;
957  }
958 
966  protected function ‪procSearchWordsByLexer(‪$searchWords)
967  {
968  $newSearchWords = [];
969  // Init lexer (used to post-processing of search words)
970  $lexerObjectClassName = ‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['lexer'] ?: \TYPO3\CMS\IndexedSearch\Lexer::class;
971  $this->lexerObj = GeneralUtility::makeInstance($lexerObjectClassName);
972  // Traverse the search word array
973  foreach (‪$searchWords as $wordDef) {
974  // No space in word (otherwise it might be a sentense in quotes like "there is").
975  if (strpos($wordDef['sword'], ' ') === false) {
976  // Split the search word by lexer:
977  $res = $this->lexerObj->split2Words($wordDef['sword']);
978  // Traverse lexer result and add all words again:
979  foreach ($res as $word) {
980  $newSearchWords[] = [
981  'sword' => $word,
982  'oper' => $wordDef['oper']
983  ];
984  }
985  } else {
986  $newSearchWords[] = $wordDef;
987  }
988  }
989  return $newSearchWords;
990  }
991 
998  public function ‪formAction($search = [])
999  {
1000  ‪$searchData = $this->‪initialize($search);
1001  // Adding search field value
1002  $this->view->assign('sword', $this->‪getSword());
1003  // Extended search
1004  if (!empty(‪$searchData['extendedSearch'])) {
1005  $this->view->assignMultiple($this->‪processExtendedSearchParameters());
1006  }
1007  $this->view->assign('searchParams', ‪$searchData);
1008  }
1009 
1013  public function ‪noTypoScriptAction()
1014  {
1015  }
1016 
1017  /****************************************
1018  * building together the available options for every dropdown
1019  ***************************************/
1025  protected function ‪getAllAvailableSearchTypeOptions()
1026  {
1027  $allOptions = [];
1028  $types = [0, 1, 2, 3, 10, 20];
1029  $blindSettings = $this->settings['blind'];
1030  if (!$blindSettings['searchType']) {
1031  foreach ($types as $typeNum) {
1032  $allOptions[$typeNum] = ‪LocalizationUtility::translate('searchTypes.' . $typeNum, 'IndexedSearch');
1033  }
1034  }
1035  // Remove this option if metaphone search is disabled)
1036  if (!$this->enableMetaphoneSearch) {
1037  unset($allOptions[10]);
1038  }
1039  // disable single entries by TypoScript
1040  $allOptions = $this->‪removeOptionsFromOptionList($allOptions, $blindSettings['searchType']);
1041  return $allOptions;
1042  }
1043 
1049  protected function ‪getAllAvailableOperandsOptions()
1050  {
1051  $allOptions = [];
1052  $blindSettings = $this->settings['blind'];
1053  if (!$blindSettings['defaultOperand']) {
1054  $allOptions = [
1055  0 => ‪LocalizationUtility::translate('defaultOperands.0', 'IndexedSearch'),
1056  1 => ‪LocalizationUtility::translate('defaultOperands.1', 'IndexedSearch')
1057  ];
1058  }
1059  // disable single entries by TypoScript
1060  $allOptions = $this->‪removeOptionsFromOptionList($allOptions, $blindSettings['defaultOperand']);
1061  return $allOptions;
1062  }
1063 
1069  protected function ‪getAllAvailableMediaTypesOptions()
1070  {
1071  $allOptions = [];
1072  $mediaTypes = [-1, 0, -2];
1073  $blindSettings = $this->settings['blind'];
1074  if (!$blindSettings['mediaType']) {
1075  foreach ($mediaTypes as $mediaType) {
1076  $allOptions[$mediaType] = ‪LocalizationUtility::translate('mediaTypes.' . $mediaType, 'IndexedSearch');
1077  }
1078  // Add media to search in:
1079  $additionalMedia = trim($this->settings['mediaList']);
1080  if ($additionalMedia !== '') {
1081  $additionalMedia = GeneralUtility::trimExplode(',', $additionalMedia, true);
1082  } else {
1083  $additionalMedia = [];
1084  }
1085  foreach ($this->externalParsers as $extension => $obj) {
1086  // Skip unwanted extensions
1087  if (!empty($additionalMedia) && !in_array($extension, $additionalMedia)) {
1088  continue;
1089  }
1090  if ($name = $obj->searchTypeMediaTitle($extension)) {
1091  $translatedName = ‪LocalizationUtility::translate('mediaTypes.' . $extension, 'IndexedSearch');
1092  $allOptions[$extension] = $translatedName ?: $name;
1093  }
1094  }
1095  }
1096  // disable single entries by TypoScript
1097  $allOptions = $this->‪removeOptionsFromOptionList($allOptions, $blindSettings['mediaType']);
1098  return $allOptions;
1099  }
1100 
1106  protected function ‪getAllAvailableLanguageOptions()
1107  {
1108  $allOptions = [
1109  '-1' => ‪LocalizationUtility::translate('languageUids.-1', 'IndexedSearch')
1110  ];
1111  $blindSettings = $this->settings['blind'];
1112  if (!$blindSettings['languageUid']) {
1113  try {
1114  $site = GeneralUtility::makeInstance(SiteFinder::class)
1115  ->getSiteByPageId(‪$GLOBALS['TSFE']->id);
1116 
1117  $languages = $site->getLanguages();
1118  foreach ($languages as $language) {
1119  $allOptions[$language->getLanguageId()] = $language->getNavigationTitle() ?? $language->getTitle();
1120  }
1121  } catch (SiteNotFoundException $e) {
1122  // No Site or pseudo site found, no options
1123  $allOptions = [];
1124  }
1126  // disable single entries by TypoScript
1127  $allOptions = $this->‪removeOptionsFromOptionList($allOptions, $blindSettings['languageUid']);
1128  } else {
1129  $allOptions = [];
1130  }
1131  return $allOptions;
1132  }
1133 
1143  protected function ‪getAllAvailableSectionsOptions()
1144  {
1145  $allOptions = [];
1146  $sections = [0, -1, -2, -3];
1147  $blindSettings = $this->settings['blind'];
1148  if (!$blindSettings['sections']) {
1149  foreach ($sections as $section) {
1150  $allOptions[$section] = ‪LocalizationUtility::translate('sections.' . $section, 'IndexedSearch');
1151  }
1152  }
1153  // Creating levels for section menu:
1154  // This selects the first and secondary menus for the "sections" selector - so we can search in sections and sub sections.
1155  if ($this->settings['displayLevel1Sections']) {
1156  $firstLevelMenu = $this->‪getMenuOfPages($this->searchRootPageIdList);
1157  $labelLevel1 = ‪LocalizationUtility::translate('sections.rootLevel1', 'IndexedSearch');
1158  $labelLevel2 = ‪LocalizationUtility::translate('sections.rootLevel2', 'IndexedSearch');
1159  foreach ($firstLevelMenu as $firstLevelKey => $menuItem) {
1160  if (!$menuItem['nav_hide']) {
1161  $allOptions['rl1_' . $menuItem['uid']] = trim($labelLevel1 . ' ' . $menuItem['title']);
1162  if ($this->settings['displayLevel2Sections']) {
1163  $secondLevelMenu = $this->‪getMenuOfPages($menuItem['uid']);
1164  foreach ($secondLevelMenu as $secondLevelKey => $menuItemLevel2) {
1165  if (!$menuItemLevel2['nav_hide']) {
1166  $allOptions['rl2_' . $menuItemLevel2['uid']] = trim($labelLevel2 . ' ' . $menuItemLevel2['title']);
1167  } else {
1168  unset($secondLevelMenu[$secondLevelKey]);
1169  }
1170  }
1171  $allOptions['rl2_' . implode(',', array_keys($secondLevelMenu))] = ‪LocalizationUtility::translate('sections.rootLevel2All', 'IndexedSearch');
1172  }
1173  } else {
1174  unset($firstLevelMenu[$firstLevelKey]);
1175  }
1176  }
1177  $allOptions['rl1_' . implode(',', array_keys($firstLevelMenu))] = ‪LocalizationUtility::translate('sections.rootLevel1All', 'IndexedSearch');
1178  }
1179  // disable single entries by TypoScript
1180  $allOptions = $this->‪removeOptionsFromOptionList($allOptions, $blindSettings['sections']);
1181  return $allOptions;
1182  }
1183 
1190  {
1191  $allOptions = [
1192  '-1' => ‪LocalizationUtility::translate('indexingConfigurations.-1', 'IndexedSearch'),
1193  '-2' => ‪LocalizationUtility::translate('indexingConfigurations.-2', 'IndexedSearch'),
1194  '0' => ‪LocalizationUtility::translate('indexingConfigurations.0', 'IndexedSearch')
1195  ];
1196  $blindSettings = $this->settings['blind'];
1197  if (!$blindSettings['indexingConfigurations']) {
1198  // add an additional index configuration
1199  if ($this->settings['defaultFreeIndexUidList']) {
1200  $uidList = GeneralUtility::intExplode(',', $this->settings['defaultFreeIndexUidList']);
1201  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1202  ->getQueryBuilderForTable('index_config');
1203  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
1204  $result = $queryBuilder
1205  ->select('uid', 'title')
1206  ->from('index_config')
1207  ->where(
1208  $queryBuilder->expr()->in(
1209  'uid',
1210  $queryBuilder->createNamedParameter($uidList, Connection::PARAM_INT_ARRAY)
1211  )
1212  )
1213  ->execute();
1214 
1215  while ($row = $result->fetch()) {
1216  $allOptions[$row['uid']] = $row['title'];
1217  }
1218  }
1219  // disable single entries by TypoScript
1220  $allOptions = $this->‪removeOptionsFromOptionList($allOptions, $blindSettings['indexingConfigurations']);
1221  } else {
1222  $allOptions = [];
1223  }
1224  return $allOptions;
1225  }
1226 
1236  protected function ‪getAllAvailableSortOrderOptions()
1237  {
1238  $allOptions = [];
1239  $sortOrders = ['rank_flag', 'rank_freq', 'rank_first', 'rank_count', 'mtime', 'title', 'crdate'];
1240  $blindSettings = $this->settings['blind'];
1241  if (!$blindSettings['sortOrder']) {
1242  foreach ($sortOrders as $order) {
1243  $allOptions[$order] = ‪LocalizationUtility::translate('sortOrders.' . $order, 'IndexedSearch');
1244  }
1245  }
1246  // disable single entries by TypoScript
1247  $allOptions = $this->‪removeOptionsFromOptionList($allOptions, $blindSettings['sortOrder.']);
1248  return $allOptions;
1249  }
1250 
1256  protected function ‪getAllAvailableGroupOptions()
1257  {
1258  $allOptions = [];
1259  $blindSettings = $this->settings['blind'];
1260  if (!$blindSettings['groupBy']) {
1261  $allOptions = [
1262  'sections' => ‪LocalizationUtility::translate('groupBy.sections', 'IndexedSearch'),
1263  'flat' => ‪LocalizationUtility::translate('groupBy.flat', 'IndexedSearch')
1264  ];
1265  }
1266  // disable single entries by TypoScript
1267  $allOptions = $this->‪removeOptionsFromOptionList($allOptions, $blindSettings['groupBy.']);
1268  return $allOptions;
1269  }
1270 
1276  protected function ‪getAllAvailableSortDescendingOptions()
1277  {
1278  $allOptions = [];
1279  $blindSettings = $this->settings['blind'];
1280  if (!$blindSettings['descending']) {
1281  $allOptions = [
1282  0 => ‪LocalizationUtility::translate('sortOrders.descending', 'IndexedSearch'),
1283  1 => ‪LocalizationUtility::translate('sortOrders.ascending', 'IndexedSearch')
1284  ];
1285  }
1286  // disable single entries by TypoScript
1287  $allOptions = $this->‪removeOptionsFromOptionList($allOptions, $blindSettings['descending.']);
1288  return $allOptions;
1289  }
1290 
1297  {
1298  $allOptions = [];
1299  if (count($this->availableResultsNumbers) > 1) {
1300  $allOptions = array_combine($this->availableResultsNumbers, $this->availableResultsNumbers);
1301  }
1302  // disable single entries by TypoScript
1303  $allOptions = $this->‪removeOptionsFromOptionList($allOptions, $this->settings['blind']['numberOfResults']);
1304  return $allOptions;
1305  }
1306 
1314  protected function ‪removeOptionsFromOptionList($allOptions, $blindOptions)
1315  {
1316  if (is_array($blindOptions)) {
1317  foreach ($blindOptions as $key => $val) {
1318  if ($val == 1) {
1319  unset($allOptions[$key]);
1320  }
1321  }
1322  }
1323  return $allOptions;
1324  }
1325 
1334  protected function ‪linkPage($pageUid, $row = [], $markUpSwParams = [])
1335  {
1336  $pageLanguage = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('language', 'contentId', 0);
1337  // Parameters for link
1338  $urlParameters = (array)unserialize($row['cHashParams']);
1339  if ($row['static_page_arguments'] !== null) {
1340  $urlParameters = array_replace_recursive($urlParameters, json_decode($row['static_page_arguments'], true));
1341  }
1342  // Add &type and &MP variable:
1343  if ($row['data_page_mp']) {
1344  $urlParameters['MP'] = $row['data_page_mp'];
1345  }
1346  if (($pageLanguage === 0 && $row['sys_language_uid'] > 0) || $pageLanguage > 0) {
1347  $urlParameters['L'] = (int)$row['sys_language_uid'];
1348  }
1349  // markup-GET vars:
1350  $urlParameters = array_merge($urlParameters, $markUpSwParams);
1351  // This will make sure that the path is retrieved if it hasn't been
1352  // already. Used only for the sake of the domain_record thing.
1353  if (!is_array($this->domainRecords[$pageUid])) {
1354  $this->‪getPathFromPageId($pageUid);
1355  }
1356 
1357  return $this->‪preparePageLink($pageUid, $row, $urlParameters);
1358  }
1359 
1366  protected function ‪getMenuOfPages($pageUid)
1367  {
1368  $pageRepository = GeneralUtility::makeInstance(PageRepository::class);
1369  if ($this->settings['displayLevelxAllTypes']) {
1370  return $pageRepository->getMenuForPages([$pageUid]);
1371  }
1372  return $pageRepository->getMenu($pageUid);
1373  }
1374 
1382  protected function ‪getPathFromPageId($id, $pathMP = '')
1383  {
1384  $identStr = $id . '|' . $pathMP;
1385  if (!isset($this->pathCache[$identStr])) {
1386  $this->requiredFrontendUsergroups[$id] = [];
1387  $this->domainRecords[$id] = [];
1388  try {
1389  $rl = GeneralUtility::makeInstance(RootlineUtility::class, $id, $pathMP)->get();
1390  $path = '';
1391  $pageCount = count($rl);
1392  if (!empty($rl)) {
1393  $excludeDoktypesFromPath = GeneralUtility::trimExplode(
1394  ',',
1395  $this->settings['results']['pathExcludeDoktypes'] ?? '',
1396  true
1397  );
1398  $breadcrumbWrap = $this->settings['breadcrumbWrap'] ?? '/';
1399  $breadcrumbWraps = GeneralUtility::makeInstance(TypoScriptService::class)
1400  ->explodeConfigurationForOptionSplit(['wrap' => $breadcrumbWrap], $pageCount);
1401  foreach ($rl as $k => $v) {
1402  if (in_array($v['doktype'], $excludeDoktypesFromPath, false)) {
1403  continue;
1404  }
1405  // Check fe_user
1406  if ($v['fe_group'] && ($v['uid'] == $id || $v['extendToSubpages'])) {
1407  $this->requiredFrontendUsergroups[$id][] = $v['fe_group'];
1408  }
1409  // Check sys_domain
1410  if ($this->settings['detectDomainRecords']) {
1411  $domainName = $this->‪getFirstDomainForPage((int)$v['uid']);
1412  if ($domainName) {
1413  $this->domainRecords[$id][] = $domainName;
1414  // Set path accordingly
1415  $path = $domainName . $path;
1416  break;
1417  }
1418  }
1419  // Stop, if we find that the current id is the current root page.
1420  if ($v['uid'] == ‪$GLOBALS['TSFE']->config['rootLine'][0]['uid']) {
1421  array_pop($breadcrumbWraps);
1422  break;
1423  }
1424  $path = ‪$GLOBALS['TSFE']->cObj->wrap(htmlspecialchars($v['title']), array_pop($breadcrumbWraps)['wrap']) . $path;
1425  }
1426  }
1427  } catch (RootLineException $e) {
1428  $path = '';
1429  }
1430  $this->pathCache[$identStr] = $path;
1431  }
1432  return $this->pathCache[$identStr];
1433  }
1434 
1441  protected function ‪getFirstDomainForPage(int $id): string
1442  {
1443  $domain = '';
1444  try {
1445  $domain = GeneralUtility::makeInstance(SiteFinder::class)
1446  ->getSiteByRootPageId($id)
1447  ->getBase()
1448  ->getHost();
1449  } catch (‪SiteNotFoundException $e) {
1450  $pseudoSiteFinder = GeneralUtility::makeInstance(PseudoSiteFinder::class);
1451  try {
1452  $domain = trim((string)$pseudoSiteFinder->getSiteByPageId($id)->getBase(), '/');
1453  } catch (SiteNotFoundException $e) {
1454  // site was not found, we return an empty string as default
1455  }
1456  }
1457  return $domain;
1458  }
1459 
1464  protected function ‪initializeExternalParsers()
1465  {
1466  // Initialize external document parsers for icon display and other soft operations
1467  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'] ?? [] as $extension => $className) {
1468  $this->externalParsers[$extension] = GeneralUtility::makeInstance($className);
1469  // Init parser and if it returns FALSE, unset its entry again
1470  if (!$this->externalParsers[$extension]->softInit($extension)) {
1471  unset($this->externalParsers[$extension]);
1472  }
1473  }
1474  }
1475 
1482  protected function ‪hookRequest($functionName)
1483  {
1484  // Hook: menuConfig_preProcessModMenu
1485  if (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]) {
1486  $hookObj = GeneralUtility::makeInstance(‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['pi1_hooks'][$functionName]);
1487  if (method_exists($hookObj, $functionName)) {
1488  $hookObj->pObj = $this;
1489  return $hookObj;
1490  }
1491  }
1492  return null;
1493  }
1494 
1501  protected function ‪multiplePagesType($item_type)
1502  {
1503  return is_object($this->externalParsers[$item_type]) && $this->externalParsers[$item_type]->isMultiplePageExtension($item_type);
1504  }
1505 
1513  protected function ‪processExtendedSearchParameters()
1514  {
1515  $allSearchTypes = $this->‪getAllAvailableSearchTypeOptions();
1516  $allDefaultOperands = $this->‪getAllAvailableOperandsOptions();
1517  $allMediaTypes = $this->‪getAllAvailableMediaTypesOptions();
1518  $allLanguageUids = $this->‪getAllAvailableLanguageOptions();
1519  $allSortOrders = $this->‪getAllAvailableSortOrderOptions();
1520  $allSortDescendings = $this->‪getAllAvailableSortDescendingOptions();
1521 
1522  return [
1523  'allSearchTypes' => $allSearchTypes,
1524  'allDefaultOperands' => $allDefaultOperands,
1525  'showTypeSearch' => !empty($allSearchTypes) || !empty($allDefaultOperands),
1526  'allMediaTypes' => $allMediaTypes,
1527  'allLanguageUids' => $allLanguageUids,
1528  'showMediaAndLanguageSearch' => !empty($allMediaTypes) || !empty($allLanguageUids),
1529  'allSections' => $this->‪getAllAvailableSectionsOptions(),
1530  'allIndexConfigurations' => $this->‪getAllAvailableIndexConfigurationsOptions(),
1531  'allSortOrders' => $allSortOrders,
1532  'allSortDescendings' => $allSortDescendings,
1533  'showSortOrders' => !empty($allSortOrders) || !empty($allSortDescendings),
1534  'allNumberOfResults' => $this->‪getAllAvailableNumberOfResultsOptions(),
1535  'allGroups' => $this->‪getAllAvailableGroupOptions()
1536  ];
1537  }
1538 
1542  protected function ‪loadSettings()
1543  {
1544  if (!is_array($this->settings['results.'])) {
1545  $this->settings['results.'] = [];
1546  }
1547  $typoScriptArray = $this->typoScriptService->convertPlainArrayToTypoScriptArray($this->settings['results']);
1548 
1549  $this->settings['results.']['summaryCropAfter'] = ‪MathUtility::forceIntegerInRange(
1550  ‪$GLOBALS['TSFE']->cObj->stdWrap($typoScriptArray['summaryCropAfter'], $typoScriptArray['summaryCropAfter.']),
1551  10,
1552  5000,
1553  180
1554  );
1555  $this->settings['results.']['summaryCropSignifier'] = ‪$GLOBALS['TSFE']->cObj->stdWrap($typoScriptArray['summaryCropSignifier'], $typoScriptArray['summaryCropSignifier.']);
1556  $this->settings['results.']['titleCropAfter'] = ‪MathUtility::forceIntegerInRange(
1557  ‪$GLOBALS['TSFE']->cObj->stdWrap($typoScriptArray['titleCropAfter'], $typoScriptArray['titleCropAfter.']),
1558  10,
1559  500,
1560  50
1561  );
1562  $this->settings['results.']['titleCropSignifier'] = ‪$GLOBALS['TSFE']->cObj->stdWrap($typoScriptArray['titleCropSignifier'], $typoScriptArray['titleCropSignifier.']);
1563  $this->settings['results.']['markupSW_summaryMax'] = ‪MathUtility::forceIntegerInRange(
1564  ‪$GLOBALS['TSFE']->cObj->stdWrap($typoScriptArray['markupSW_summaryMax'], $typoScriptArray['markupSW_summaryMax.']),
1565  10,
1566  5000,
1567  300
1568  );
1569  $this->settings['results.']['markupSW_postPreLgd'] = ‪MathUtility::forceIntegerInRange(
1570  ‪$GLOBALS['TSFE']->cObj->stdWrap($typoScriptArray['markupSW_postPreLgd'], $typoScriptArray['markupSW_postPreLgd.']),
1571  1,
1572  500,
1573  60
1574  );
1575  $this->settings['results.']['markupSW_postPreLgd_offset'] = ‪MathUtility::forceIntegerInRange(
1576  ‪$GLOBALS['TSFE']->cObj->stdWrap($typoScriptArray['markupSW_postPreLgd_offset'], $typoScriptArray['markupSW_postPreLgd_offset.']),
1577  1,
1578  50,
1579  5
1580  );
1581  $this->settings['results.']['markupSW_divider'] = ‪$GLOBALS['TSFE']->cObj->stdWrap($typoScriptArray['markupSW_divider'], $typoScriptArray['markupSW_divider.']);
1582  $this->settings['results.']['hrefInSummaryCropAfter'] = ‪MathUtility::forceIntegerInRange(
1583  ‪$GLOBALS['TSFE']->cObj->stdWrap($typoScriptArray['hrefInSummaryCropAfter'], $typoScriptArray['hrefInSummaryCropAfter.']),
1584  10,
1585  400,
1586  60
1587  );
1588  $this->settings['results.']['hrefInSummaryCropSignifier'] = ‪$GLOBALS['TSFE']->cObj->stdWrap($typoScriptArray['hrefInSummaryCropSignifier'], $typoScriptArray['hrefInSummaryCropSignifier.']);
1589  }
1590 
1597  protected function ‪getNumberOfResults($numberOfResults)
1598  {
1599  $numberOfResults = (int)$numberOfResults;
1600 
1601  return in_array($numberOfResults, $this->availableResultsNumbers) ?
1602  $numberOfResults : ‪$this->defaultResultNumber;
1603  }
1604 
1614  protected function ‪preparePageLink(int $pageUid, array $row, array $urlParameters): array
1615  {
1616  $target = '';
1617  $uri = $this->controllerContext->getUriBuilder()
1618  ->setTargetPageUid($pageUid)
1619  ->setTargetPageType($row['data_page_type'])
1620  ->setUseCacheHash(true)
1621  ->setArguments($urlParameters)
1622  ->build();
1623 
1624  // If external domain, then link to that:
1625  if (!empty($this->domainRecords[$pageUid])) {
1626  $scheme = GeneralUtility::getIndpEnv('TYPO3_SSL') ? 'https://' : 'http://';
1627  $firstDomain = reset($this->domainRecords[$pageUid]);
1628  $uri = $scheme . $firstDomain . $uri;
1629  $target = $this->settings['detectDomainRecords.']['target'];
1630  }
1631 
1632  return ['uri' => $uri, 'target' => $target];
1633  }
1634 
1642  protected function ‪linkPageATagWrap(string $linkText, array $linkData): string
1643  {
1644  $attributes = [
1645  'href' => $linkData['uri']
1646  ];
1647  if (!empty($linkData['target'])) {
1648  $attributes['target'] = $linkData['target'];
1649  }
1650  return sprintf(
1651  '<a %s>%s</a>',
1652  GeneralUtility::implodeAttributes($attributes, true),
1653  htmlspecialchars($linkText, ENT_QUOTES | ENT_HTML5)
1654  );
1655  }
1656 
1661  public function ‪setSword(‪$sword)
1662  {
1663  $this->sword = (string)‪$sword;
1664  }
1665 
1670  public function ‪getSword()
1671  {
1672  return (string)‪$this->sword;
1673  }
1674 }
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\multiplePagesType
‪bool multiplePagesType($item_type)
Definition: SearchController.php:1483
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\markupSWpartsOfString
‪string markupSWpartsOfString($str)
Definition: SearchController.php:755
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\makeDescription
‪string makeDescription($row, $noMarkup=false, $length=180)
Definition: SearchController.php:715
‪TYPO3\CMS\IndexedSearch\Controller\SearchController
Definition: SearchController.php:46
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\noTypoScriptAction
‪noTypoScriptAction()
Definition: SearchController.php:995
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:23
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$searchRootPageIdList
‪int string $searchRootPageIdList
Definition: SearchController.php:69
‪TYPO3\CMS\Extbase\Annotation
Definition: IgnoreValidation.php:4
‪TYPO3\CMS\Extbase\Utility\LocalizationUtility
Definition: LocalizationUtility.php:29
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$externalParsers
‪array $externalParsers
Definition: SearchController.php:94
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getAllAvailableOperandsOptions
‪array getAllAvailableOperandsOptions()
Definition: SearchController.php:1031
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$defaultResultNumber
‪int $defaultResultNumber
Definition: SearchController.php:73
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$indexerConfig
‪array $indexerConfig
Definition: SearchController.php:136
‪TYPO3\CMS\Core\Html\HtmlParser
Definition: HtmlParser.php:26
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$requiredFrontendUsergroups
‪array $requiredFrontendUsergroups
Definition: SearchController.php:112
‪TYPO3\CMS\Core\Configuration\ExtensionConfiguration
Definition: ExtensionConfiguration.php:42
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getAllAvailableSearchTypeOptions
‪array getAllAvailableSearchTypeOptions()
Definition: SearchController.php:1007
‪TYPO3\CMS\Core\Utility\PathUtility\stripPathSitePrefix
‪static string stripPathSitePrefix($path)
Definition: PathUtility.php:371
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\formAction
‪formAction($search=[])
Definition: SearchController.php:980
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$searchRepository
‪TYPO3 CMS IndexedSearch Domain Repository IndexSearchRepository $searchRepository
Definition: SearchController.php:83
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getPathFromPageId
‪string getPathFromPageId($id, $pathMP='')
Definition: SearchController.php:1364
‪TYPO3
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getAllAvailableGroupOptions
‪array getAllAvailableGroupOptions()
Definition: SearchController.php:1238
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$pathCache
‪array $pathCache
Definition: SearchController.php:124
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\compileSingleResultRow
‪array compileSingleResultRow($row, $headerOnly=0)
Definition: SearchController.php:446
‪TYPO3\CMS\Core\Utility\RootlineUtility
Definition: RootlineUtility.php:36
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getFirstDomainForPage
‪string getFirstDomainForPage(int $id)
Definition: SearchController.php:1423
‪TYPO3\CMS\Core\Exception\SiteNotFoundException
Definition: SiteNotFoundException.php:25
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getMenuOfPages
‪array getMenuOfPages($pageUid)
Definition: SearchController.php:1348
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\compileResultRows
‪array compileResultRows($resultRows, $freeIndexUid=-1)
Definition: SearchController.php:361
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$iconFileNameCache
‪array $iconFileNameCache
Definition: SearchController.php:130
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getSword
‪string getSword()
Definition: SearchController.php:1652
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:49
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\searchAction
‪searchAction($search=[])
Definition: SearchController.php:242
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\writeSearchStat
‪writeSearchStat($searchParams, $searchWords, $count, $pt)
Definition: SearchController.php:833
‪TYPO3\CMS\Core\Utility\IpAnonymizationUtility
Definition: IpAnonymizationUtility.php:24
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getAllAvailableIndexConfigurationsOptions
‪array getAllAvailableIndexConfigurationsOptions()
Definition: SearchController.php:1171
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getAllAvailableSortOrderOptions
‪array getAllAvailableSortOrderOptions()
Definition: SearchController.php:1218
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\linkPageATagWrap
‪string linkPageATagWrap(string $linkText, array $linkData)
Definition: SearchController.php:1624
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\hookRequest
‪object null hookRequest($functionName)
Definition: SearchController.php:1464
‪TYPO3\CMS\Core\Site\PseudoSiteFinder
Definition: PseudoSiteFinder.php:39
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\linkPage
‪array linkPage($pageUid, $row=[], $markUpSwParams=[])
Definition: SearchController.php:1316
‪TYPO3\CMS\IndexedSearch\Controller
Definition: AdministrationController.php:2
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\setSword
‪setSword($sword)
Definition: SearchController.php:1643
‪TYPO3\CMS\Extbase\Utility\LocalizationUtility\translate
‪static string null translate($key, $extensionName=null, $arguments=null, string $languageKey=null, array $alternativeLanguageKeys=null)
Definition: LocalizationUtility.php:63
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\initialize
‪array initialize($searchData=[])
Definition: SearchController.php:162
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$lexerObj
‪TYPO3 CMS IndexedSearch Lexer $lexerObj
Definition: SearchController.php:89
‪TYPO3\CMS\Frontend\Page\PageRepository
Definition: PageRepository.php:53
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\injectTypoScriptService
‪injectTypoScriptService(\TYPO3\CMS\Core\TypoScript\TypoScriptService $typoScriptService)
Definition: SearchController.php:151
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$searchWords
‪array $searchWords
Definition: SearchController.php:55
‪TYPO3\CMS\Extbase\Mvc\Controller\AbstractController\redirect
‪redirect($actionName, $controllerName=null, $extensionName=null, array $arguments=null, $pageUid=null, $delay=0, $statusCode=303)
Definition: AbstractController.php:284
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$resultSections
‪array $resultSections
Definition: SearchController.php:118
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$firstRow
‪array $firstRow
Definition: SearchController.php:100
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\makeLanguageIndication
‪string makeLanguageIndication($row)
Definition: SearchController.php:635
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\procSearchWordsByLexer
‪array procSearchWordsByLexer($searchWords)
Definition: SearchController.php:948
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\removeOptionsFromOptionList
‪array removeOptionsFromOptionList($allOptions, $blindOptions)
Definition: SearchController.php:1296
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getAllAvailableMediaTypesOptions
‪array getAllAvailableMediaTypesOptions()
Definition: SearchController.php:1051
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$typoScriptService
‪TYPO3 CMS Core TypoScript TypoScriptService $typoScriptService
Definition: SearchController.php:146
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$domainRecords
‪array $domainRecords
Definition: SearchController.php:106
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getSpecialConfigurationForResultRow
‪array getSpecialConfigurationForResultRow($row)
Definition: SearchController.php:572
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$sword
‪string $sword
Definition: SearchController.php:51
‪TYPO3\CMS\Core\Type\File\ImageInfo
Definition: ImageInfo.php:25
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\loadSettings
‪loadSettings()
Definition: SearchController.php:1524
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getDisplayResults
‪array getDisplayResults($searchWords, $resultData, $freeIndexUid=-1)
Definition: SearchController.php:319
‪TYPO3\CMS\Core\TypoScript\TypoScriptService
Definition: TypoScriptService.php:23
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$availableResultsNumbers
‪int[] $availableResultsNumbers
Definition: SearchController.php:77
‪$output
‪$output
Definition: annotationChecker.php:113
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:31
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\makeRating
‪string makeRating($row)
Definition: SearchController.php:599
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$searchData
‪array $searchData
Definition: SearchController.php:59
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getNumberOfResults
‪int getNumberOfResults($numberOfResults)
Definition: SearchController.php:1579
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\processExtendedSearchParameters
‪array processExtendedSearchParameters()
Definition: SearchController.php:1495
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Extbase\Mvc\Controller\ActionController
Definition: ActionController.php:31
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:21
‪TYPO3\CMS\Core\Exception\Page\RootLineException
Definition: RootLineException.php:24
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\preparePageLink
‪array preparePageLink(int $pageUid, array $row, array $urlParameters)
Definition: SearchController.php:1596
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\$enableMetaphoneSearch
‪bool $enableMetaphoneSearch
Definition: SearchController.php:142
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getSearchWords
‪array getSearchWords($defaultOperator)
Definition: SearchController.php:898
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Core\Utility\PathUtility\getAbsoluteWebPath
‪static string getAbsoluteWebPath($targetPath)
Definition: PathUtility.php:42
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer
Definition: FrontendRestrictionContainer.php:29
‪TYPO3\CMS\Core\Utility\IpAnonymizationUtility\anonymizeIp
‪static string anonymizeIp(string $address, int $mask=null)
Definition: IpAnonymizationUtility.php:60
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getAllAvailableLanguageOptions
‪array getAllAvailableLanguageOptions()
Definition: SearchController.php:1088
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\makeItemTypeIcon
‪string makeItemTypeIcon($imageType, $alt, $specRowConf)
Definition: SearchController.php:660
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getAllAvailableSortDescendingOptions
‪array getAllAvailableSortDescendingOptions()
Definition: SearchController.php:1258
‪TYPO3\CMS\IndexedSearch\Utility\IndexedSearchUtility\getExplodedSearchString
‪static array getExplodedSearchString($sword, $defaultOperator, $operatorTranslateTable)
Definition: IndexedSearchUtility.php:59
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getAllAvailableNumberOfResultsOptions
‪array getAllAvailableNumberOfResultsOptions()
Definition: SearchController.php:1278
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\getAllAvailableSectionsOptions
‪array getAllAvailableSectionsOptions()
Definition: SearchController.php:1125
‪TYPO3\CMS\IndexedSearch\Controller\SearchController\initializeExternalParsers
‪initializeExternalParsers()
Definition: SearchController.php:1446
‪TYPO3\CMS\Core\Database\Connection\PARAM_LOB
‪const PARAM_LOB
Definition: Connection.php:52