2 namespace TYPO3\CMS\IndexedSearch\Controller
;
5 * This file is part of the TYPO3 CMS project.
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.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
16 use TYPO3\CMS\Backend\Utility\BackendUtility
;
17 use TYPO3\CMS\Backend\View\BackendTemplateView
;
18 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication
;
19 use TYPO3\CMS\Core\Configuration\ExtensionConfiguration
;
20 use TYPO3\CMS\Core\Database\ConnectionPool
;
21 use TYPO3\CMS\Core\Imaging\Icon
;
22 use TYPO3\CMS\Core\Localization\LanguageService
;
23 use TYPO3\CMS\Core\Type\Bitmask\Permission
;
24 use TYPO3\CMS\Core\Utility\GeneralUtility
;
25 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController
;
26 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface
;
27 use TYPO3\CMS\Extbase\Mvc\Web\Request
as WebRequest
;
28 use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
;
29 use TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository
;
30 use TYPO3\CMS\IndexedSearch\Indexer
;
33 * Administration controller
35 class AdministrationController
extends ActionController
38 * @var AdministrationRepository
40 protected $administrationRepository;
43 * @var int Current page id
45 protected $pageUid = 0;
48 * @var array External parsers
50 protected $external_parsers = [];
53 * @var array Configuration defined in the Extension Manager
55 protected $indexerConfig = [];
58 * @var bool is metaphone enabled
60 protected $enableMetaphoneSearch = false;
65 * @var \TYPO3\CMS\IndexedSearch\Indexer
70 * Backend Template Container
72 * @var BackendTemplateView
74 protected $defaultViewObjectName = BackendTemplateView
::class;
77 * BackendTemplateContainer
79 * @var BackendTemplateView
84 * Set up the doc header properly here
86 * @param ViewInterface $view
88 protected function initializeView(ViewInterface
$view)
90 if ($view instanceof BackendTemplateView
) {
91 /** @var BackendTemplateView $view */
92 parent
::initializeView($view);
93 $permissionClause = $this->getBackendUserAuthentication()->getPagePermsClause(Permission
::PAGE_SHOW
);
94 $pageRecord = BackendUtility
::readPageAccess($this->pageUid
, $permissionClause);
96 $view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($pageRecord);
98 $this->generateMenu();
99 $this->view
->getModuleTemplate()->setFlashMessageQueue($this->controllerContext
->getFlashMessageQueue());
100 $view->assign('extensionConfiguration', $this->indexerConfig
);
105 * Generates the action menu
107 protected function generateMenu()
111 'controller' => 'Administration',
113 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.general')
116 'controller' => 'Administration',
118 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.pages')
120 'externalDocuments' => [
121 'controller' => 'Administration',
122 'action' => 'externalDocuments',
123 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.externalDocuments')
126 'controller' => 'Administration',
127 'action' => 'statistic',
128 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.statistic')
131 $uriBuilder = $this->objectManager
->get(UriBuilder
::class);
132 $uriBuilder->setRequest($this->request
);
134 $menu = $this->view
->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
135 $menu->setIdentifier('IndexedSearchModuleMenu');
137 foreach ($menuItems as $menuItemConfig) {
138 $isActive = $this->request
->getControllerActionName() === $menuItemConfig['action'];
139 $menuItem = $menu->makeMenuItem()
140 ->setTitle($menuItemConfig['label'])
141 ->setHref($this->getHref($menuItemConfig['controller'], $menuItemConfig['action']))
142 ->setActive($isActive);
143 $menu->addMenuItem($menuItem);
146 $this->view
->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
150 * Function will be called before every other action
152 public function initializeAction()
154 $this->pageUid
= (int)GeneralUtility
::_GET('id');
155 $this->indexerConfig
= GeneralUtility
::makeInstance(ExtensionConfiguration
::class)->get('indexed_search');
156 $this->enableMetaphoneSearch
= (bool)$this->indexerConfig
['enableMetaphoneSearch'];
157 $this->indexer
= GeneralUtility
::makeInstance(Indexer
::class);
159 parent
::initializeAction();
163 * Override the action name if found in the uc of the user
165 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request
166 * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response
167 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
169 public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface
$request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface
$response)
171 $vars = GeneralUtility
::_GET('tx_indexedsearch_web_indexedsearchisearch');
173 $beUser = $this->getBackendUserAuthentication();
174 if (is_array($vars) && isset($vars['action']) && method_exists($this, $vars['action'] . 'Action')) {
175 $action = $vars['action'];
178 case 'saveStopwordsKeywords':
179 $action = 'statisticDetails';
181 case 'deleteIndexedItem':
182 $action = 'statistic';
186 $beUser->uc
['indexed_search']['action'] = $action;
187 $beUser->uc
['indexed_search']['arguments'] = $request->getArguments();
189 } elseif (isset($beUser->uc
['indexed_search']['action'])) {
190 if ($request instanceof WebRequest
) {
191 $request->setControllerActionName($beUser->uc
['indexed_search']['action']);
193 if (isset($beUser->uc
['indexed_search']['arguments'])) {
194 $request->setArguments($beUser->uc
['indexed_search']['arguments']);
198 parent
::processRequest($request, $response);
202 * @param \TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository $administrationRepository
204 public function injectAdministrationRepository(AdministrationRepository
$administrationRepository)
206 $this->administrationRepository
= $administrationRepository;
210 * Index action contains the most important statistics
212 public function indexAction()
214 $this->view
->assignMultiple([
215 'records' => $this->administrationRepository
->getRecordsNumbers(),
216 'phash' => $this->administrationRepository
->getPageHashTypes()
219 if ($this->pageUid
) {
220 $expressionBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)
221 ->getQueryBuilderForTable('index_stat_word')
224 $last24hours = $expressionBuilder->gt('tstamp', ($GLOBALS['EXEC_TIME'] - 86400));
225 $last30days = $expressionBuilder->gt('tstamp', ($GLOBALS['EXEC_TIME'] - 30 * 86400));
227 $this->view
->assignMultiple([
228 'pageUid' => $this->pageUid
,
229 'all' => $this->administrationRepository
->getGeneralSearchStatistic('', $this->pageUid
),
230 'last24hours' => $this->administrationRepository
->getGeneralSearchStatistic($last24hours, $this->pageUid
),
231 'last30days' => $this->administrationRepository
->getGeneralSearchStatistic($last30days, $this->pageUid
),
237 * Statistics for pages
239 public function pagesAction()
241 $this->view
->assign('records', $this->administrationRepository
->getPageStatistic());
245 * Statistics for external documents
247 public function externalDocumentsAction()
249 $this->view
->assign('records', $this->administrationRepository
->getExternalDocumentsStatistic());
253 * Statistics for a given page hash
255 * @param int $pageHash
257 public function statisticDetailsAction($pageHash = 0)
259 $pageHash = (int)$pageHash;
261 $icon = $this->view
->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-up', Icon
::SIZE_SMALL
);
262 $backButton = $this->view
->getModuleTemplate()->getDocHeaderComponent()
263 ->getButtonBar()->makeLinkButton()
264 ->setTitle($this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.back'))
266 ->setHref($this->getHref('Administration', 'statistic'));
267 $this->view
->getModuleTemplate()->getDocHeaderComponent()
268 ->getButtonBar()->addButton($backButton);
270 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
271 $pageHashRow = $queryBuilder
273 ->from('index_phash')
275 $queryBuilder->expr()->eq(
277 $queryBuilder->createNamedParameter($pageHash, \PDO
::PARAM_INT
)
283 if (!is_array($pageHashRow)) {
284 $this->redirect('statistic');
287 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_debug');
288 $debugRow = $queryBuilder
290 ->from('index_debug')
292 $queryBuilder->expr()->eq(
294 $queryBuilder->createNamedParameter($pageHash, \PDO
::PARAM_INT
)
301 if (is_array($debugRow)) {
302 $debugInfo = unserialize($debugRow[0]['debuginfo']);
303 $lexer = $debugInfo['lexer'];
304 unset($debugInfo['lexer']);
306 $pageRecord = BackendUtility
::getRecord('pages', $pageHashRow['data_page_id']);
307 $keywords = is_array($pageRecord) ?
array_flip(GeneralUtility
::trimExplode(',', $pageRecord['keywords'], true)) : [];
309 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_words');
310 $wordRecords = $queryBuilder
311 ->select('index_words.*', 'index_rel.*')
312 ->from('index_words')
315 $queryBuilder->expr()->eq(
317 $queryBuilder->createNamedParameter($pageHash, \PDO
::PARAM_INT
)
319 $queryBuilder->expr()->eq(
321 $queryBuilder->quoteIdentifier('index_rel.wid')
324 ->orderBy('index_words.baseword')
327 foreach ($wordRecords as $id => $row) {
328 if (isset($keywords[$row['baseword']])) {
329 $wordRecords[$id]['is_keyword'] = true;
332 $metaphoneRows = $metaphone = [];
333 if ($this->enableMetaphoneSearch
&& is_array($wordRecords)) {
334 // Group metaphone hash
335 foreach ($wordRecords as $row) {
336 $metaphoneRows[$row['metaphone']][] = $row['baseword'];
339 foreach ($metaphoneRows as $hash => $words) {
340 if (count($words) > 1) {
342 'metaphone' => $this->indexer
->metaphone($words[0], 1), $hash,
351 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_section');
352 $sections = $queryBuilder
354 ->from('index_section')
356 $queryBuilder->expr()->eq(
358 $queryBuilder->createNamedParameter($pageHash, \PDO
::PARAM_INT
)
365 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_words');
366 $topCountWords = $queryBuilder
367 ->select('index_words.baseword', 'index_words.metaphone', 'index_rel.*')
368 ->from('index_words')
372 $queryBuilder->expr()->eq(
374 $queryBuilder->createNamedParameter($pageHash, \PDO
::PARAM_INT
)
376 $queryBuilder->expr()->eq(
377 'index_words.is_stopword',
378 $queryBuilder->createNamedParameter(0, \PDO
::PARAM_INT
)
380 $queryBuilder->expr()->eq(
382 $queryBuilder->quoteIdentifier('index_rel.wid')
385 ->orderBy('index_rel.count', 'DESC')
390 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_words');
391 $topFrequency = $queryBuilder
392 ->select('index_words.baseword', 'index_words.metaphone', 'index_rel.*')
393 ->from('index_words')
397 $queryBuilder->expr()->eq(
399 $queryBuilder->createNamedParameter($pageHash, \PDO
::PARAM_INT
)
401 $queryBuilder->expr()->eq(
402 'index_words.is_stopword',
403 $queryBuilder->createNamedParameter(0, \PDO
::PARAM_INT
)
405 $queryBuilder->expr()->eq(
407 $queryBuilder->quoteIdentifier('index_rel.wid')
410 ->orderBy('index_rel.freq', 'DESC')
414 $this->view
->assignMultiple([
415 'phash' => (int)$pageHash,
416 'phashRow' => $pageHashRow,
417 'words' => $wordRecords,
418 'sections' => $sections,
419 'topCount' => $topCountWords,
420 'topFrequency' => $topFrequency,
421 'debug' => $debugInfo,
423 'metaphone' => $metaphone,
424 'page' => $pageRecord,
425 'keywords' => $keywords
430 * Save stop words and keywords
432 * @param string $pageHash
434 * @param array $stopwords
435 * @param array $keywords
437 public function saveStopwordsKeywordsAction($pageHash, $pageId, $stopwords = [], $keywords = [])
439 if ($this->getBackendUserAuthentication()->isAdmin()) {
440 if (is_array($stopwords) && !empty($stopwords)) {
441 $this->administrationRepository
->saveStopWords($stopwords);
443 if (is_array($keywords) && !empty($keywords)) {
444 $this->administrationRepository
->saveKeywords($keywords, $pageId);
448 $this->redirect('statisticDetails', null, null, ['pageHash' => $pageHash]);
452 * Statistics for a given word id
455 * @param int $pageHash
457 public function wordDetailAction($id = 0, $pageHash = 0)
459 $queryBuilder = GeneralUtility
::makeInstance(ConnectionPool
::class)->getQueryBuilderForTable('index_phash');
460 $rows = $queryBuilder
461 ->select('index_phash.*', 'index_section.*', 'index_rel.*')
463 ->from('index_section')
464 ->from('index_phash')
466 $queryBuilder->expr()->eq(
468 $queryBuilder->createNamedParameter($id, \PDO
::PARAM_INT
)
470 $queryBuilder->expr()->eq(
472 $queryBuilder->quoteIdentifier('index_section.phash')
474 $queryBuilder->expr()->eq(
475 'index_section.phash',
476 $queryBuilder->quoteIdentifier('index_phash.phash')
479 ->orderBy('index_rel.freq', 'desc')
483 $this->view
->assignMultiple([
493 * @param string $mode
495 public function statisticAction($depth = 1, $mode = 'overview')
497 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'] ??
[] as $extension => $className) {
498 /** @var \TYPO3\CMS\IndexedSearch\FileContentParser $fileContentParser */
499 $fileContentParser = GeneralUtility
::makeInstance($className);
500 if ($fileContentParser->softInit($extension)) {
501 $this->external_parsers
[$extension] = $fileContentParser;
504 $this->administrationRepository
->external_parsers
= $this->external_parsers
;
506 $allLines = $this->administrationRepository
->getTree($this->pageUid
, $depth, $mode);
508 $this->view
->assignMultiple([
509 'levelTranslations' => explode('|', $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.enterSearchLevels')),
511 'pageUid' => $this->pageUid
,
518 * Remove item from index
522 * @param string $mode
524 public function deleteIndexedItemAction($id, $depth = 1, $mode = 'overview')
526 $this->administrationRepository
->removeIndexedPhashRow($id, $this->pageUid
, $depth);
527 $this->redirect('statistic', null, null, ['depth' => $depth, 'mode' => $mode]);
531 * Creates te URI for a backend action
533 * @param string $controller
534 * @param string $action
535 * @param array $parameters
539 protected function getHref($controller, $action, $parameters = [])
541 $uriBuilder = $this->objectManager
->get(UriBuilder
::class);
542 $uriBuilder->setRequest($this->request
);
543 return $uriBuilder->reset()->uriFor($action, $parameters, $controller);
547 * @return BackendUserAuthentication
549 protected function getBackendUserAuthentication()
551 return $GLOBALS['BE_USER'];
555 * @return LanguageService
557 protected function getLanguageService()
559 return $GLOBALS['LANG'];