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!
17 use TYPO3\CMS\Backend\View\BackendTemplateView
;
18 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication
;
19 use TYPO3\CMS\Core\Database\DatabaseConnection
;
20 use TYPO3\CMS\Core\Imaging\Icon
;
21 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController
;
22 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface
;
23 use TYPO3\CMS\Extbase\Mvc\Web\Request
as WebRequest
;
24 use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder
;
25 use TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository
;
26 use TYPO3\CMS\Backend\Utility\BackendUtility
;
27 use TYPO3\CMS\Core\Utility\GeneralUtility
;
28 use TYPO3\CMS\IndexedSearch\Indexer
;
29 use TYPO3\CMS\Lang\LanguageService
;
32 * Administration controller
34 class AdministrationController
extends ActionController
{
37 * @var AdministrationRepository
39 protected $administrationRepository;
42 * @var int Current page id
44 protected $pageUid = 0;
47 * @var array External parsers
49 protected $external_parsers = array();
52 * @var array Configuration defined in the Extension Manager
54 protected $indexerConfig = array();
57 * @var bool is metaphone enabled
59 protected $enableMetaphoneSearch = FALSE
;
64 * @var \TYPO3\CMS\IndexedSearch\Indexer
69 * Backend Template Container
71 * @var BackendTemplateView
73 protected $defaultViewObjectName = BackendTemplateView
::class;
76 * BackendTemplateContainer
78 * @var BackendTemplateView
83 * Set up the doc header properly here
85 * @param ViewInterface $view
87 protected function initializeView(ViewInterface
$view) {
88 /** @var BackendTemplateView $view */
89 parent
::initializeView($view);
90 $permissionClause = $this->getBackendUserAuthentication()->getPagePermsClause(1);
91 $pageRecord = BackendUtility
::readPageAccess($this->pageUid
, $permissionClause);
92 $view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($pageRecord);
93 $this->generateMenu();
97 * Generates the action menu
99 protected function generateMenu() {
102 'controller' => 'Administration',
104 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.general')
107 'controller' => 'Administration',
109 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.pages')
111 'externalDocuments' => [
112 'controller' => 'Administration',
113 'action' => 'externalDocuments',
114 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.externalDocuments')
117 'controller' => 'Administration',
118 'action' => 'statistic',
119 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.statistic')
122 $uriBuilder = $this->objectManager
->get(UriBuilder
::class);
123 $uriBuilder->setRequest($this->request
);
125 $menu = $this->view
->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
126 $menu->setIdentifier('IndexedSearchModuleMenu');
128 foreach ($menuItems as $menuItemConfig) {
129 $isActive = $this->request
->getControllerActionName() === $menuItemConfig['action'];
130 $menuItem = $menu->makeMenuItem()
131 ->setTitle($menuItemConfig['label'])
132 ->setHref($this->getHref($menuItemConfig['controller'], $menuItemConfig['action']))
133 ->setActive($isActive);
134 $menu->addMenuItem($menuItem);
137 $this->view
->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
141 * Function will be called before every other action
145 public function initializeAction() {
146 $this->pageUid
= (int)GeneralUtility
::_GET('id');
147 $this->indexerConfig
= unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['indexed_search']);
148 $this->enableMetaphoneSearch
= (bool
)$this->indexerConfig
['enableMetaphoneSearch'];
149 $this->indexer
= GeneralUtility
::makeInstance(Indexer
::class);
151 parent
::initializeAction();
155 * Override the action name if found in the uc of the user
157 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request
158 * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response
159 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
161 public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface
$request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface
$response) {
162 $vars = GeneralUtility
::_GET('tx_indexedsearch_web_indexedsearchisearch');
164 $beUser = $this->getBackendUserAuthentication();
165 if (is_array($vars) && isset($vars['action']) && method_exists($this, $vars['action'] . 'Action')) {
166 $action = $vars['action'];
169 case 'saveStopwordsKeywords':
170 $action = 'statisticDetails';
172 case 'deleteIndexedItem':
173 $action = 'statistic';
177 $beUser->uc
['indexed_search']['action'] = $action;
178 $beUser->uc
['indexed_search']['arguments'] = $request->getArguments();
180 } elseif (isset($beUser->uc
['indexed_search']['action'])) {
181 if ($request instanceof WebRequest
) {
182 $request->setControllerActionName($beUser->uc
['indexed_search']['action']);
184 if (isset($beUser->uc
['indexed_search']['arguments'])) {
185 $request->setArguments($beUser->uc
['indexed_search']['arguments']);
189 parent
::processRequest($request, $response);
193 * @param \TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository $administrationRepository
196 public function injectAdministrationRepository(AdministrationRepository
$administrationRepository) {
197 $this->administrationRepository
= $administrationRepository;
201 * Index action contains the most important statistics
205 public function indexAction() {
206 $this->view
->assignMultiple(array(
207 'records' => $this->administrationRepository
->getRecordsNumbers(),
208 'phash' => $this->administrationRepository
->getPageHashTypes()
211 if ($this->pageUid
) {
212 $last24hours = ' AND tstamp > ' . ($GLOBALS['EXEC_TIME'] - 24 * 60 * 60);
213 $last30days = ' AND tstamp > ' . ($GLOBALS['EXEC_TIME'] - 30 * 24 * 60 * 60);
215 $this->view
->assignMultiple(array(
216 'pageUid' => $this->pageUid
,
217 'all' => $this->administrationRepository
->getGeneralSearchStatistic('', $this->pageUid
),
218 'last24hours' => $this->administrationRepository
->getGeneralSearchStatistic($last24hours, $this->pageUid
),
219 'last30days' => $this->administrationRepository
->getGeneralSearchStatistic($last30days, $this->pageUid
),
225 * Statistics for pages
229 public function pagesAction() {
230 $this->view
->assign('records', $this->administrationRepository
->getPageStatistic());
234 * Statistics for external documents
238 public function externalDocumentsAction() {
239 $this->view
->assign('records', $this->administrationRepository
->getExternalDocumentsStatistic());
243 * Statistics for a given page hash
245 * @param int $pageHash
248 public function statisticDetailsAction($pageHash = 0) {
250 $icon = $this->view
->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-up', Icon
::SIZE_SMALL
);
251 $backButton = $this->view
->getModuleTemplate()->getDocHeaderComponent()
252 ->getButtonBar()->makeLinkButton()
253 ->setTitle($this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.back'))
255 ->setHref($this->getHref('Administration', 'statistic'));
256 $this->view
->getModuleTemplate()->getDocHeaderComponent()
257 ->getButtonBar()->addButton($backButton);
259 $pageHash = (int)$pageHash;
260 $db = $this->getDatabaseConnection();
261 $pageHashRow = $db->exec_SELECTgetSingleRow('*', 'index_phash', 'phash = ' . (int)$pageHash);
263 if (!is_array($pageHashRow)) {
264 $this->redirect('statistic');
267 $debugRow = $db->exec_SELECTgetRows('*', 'index_debug', 'phash = ' . (int)$pageHash);
268 $debugInfo = array();
270 if (is_array($debugRow)) {
271 $debugInfo = unserialize($debugRow[0]['debuginfo']);
272 $lexer = $debugInfo['lexer'];
273 unset($debugInfo['lexer']);
275 $pageRecord = BackendUtility
::getRecord('pages', $pageHashRow['data_page_id']);
276 $keywords = is_array($pageRecord) ?
array_flip(GeneralUtility
::trimExplode(',', $pageRecord['keywords'], TRUE
)) : array();
277 $wordRecords = $db->exec_SELECTgetRows(
278 'index_words.*, index_rel.*',
279 'index_rel, index_words',
280 'index_rel.phash = ' . (int)$pageHash . ' AND index_words.wid = index_rel.wid',
282 'index_words.baseword'
284 foreach($wordRecords as $id => $row) {
285 if (isset($keywords[$row['baseword']])) {
286 $wordRecords[$id]['is_keyword'] = TRUE
;
289 $metaphoneRows = $metaphone = array();
290 if ($this->enableMetaphoneSearch
&& is_array($wordRecords)) {
291 // Group metaphone hash
292 foreach ($wordRecords as $row) {
293 $metaphoneRows[$row['metaphone']][] = $row['baseword'];
296 foreach ($metaphoneRows as $hash => $words) {
297 if (count($words) > 1) {
298 $metaphone[] = array(
299 'metaphone' => $this->indexer
->metaphone($words[0], 1), $hash,
306 $this->view
->assignMultiple(array(
307 'phash' => $pageHash,
308 'phashRow' => $pageHashRow,
309 'words' => $wordRecords,
310 'sections' => $db->exec_SELECTgetRows(
313 'index_section.phash = ' . (int)$pageHash
315 'topCount' => $db->exec_SELECTgetRows(
316 'index_words.baseword, index_words.metaphone, index_rel.*',
317 'index_rel, index_words',
318 'index_rel.phash = ' . (int)$pageHash . ' AND index_words.wid = index_rel.wid
319 AND index_words.is_stopword=0',
321 'index_rel.count DESC',
324 'topFrequency' => $db->exec_SELECTgetRows(
325 'index_words.baseword, index_words.metaphone, index_rel.*',
326 'index_rel, index_words',
327 'index_rel.phash = ' . (int)$pageHash . ' AND index_words.wid = index_rel.wid
328 AND index_words.is_stopword=0',
330 'index_rel.freq DESC',
333 'debug' => $debugInfo,
335 'metaphone' => $metaphone,
336 'page' => $pageRecord,
337 'keywords' => $keywords
342 * Save stop words and keywords
344 * @param string $pageHash
346 * @param array $stopwords
347 * @param array $keywords
350 public function saveStopwordsKeywordsAction($pageHash, $pageId, $stopwords = array(), $keywords = array()) {
351 if ($this->getBackendUserAuthentication()->isAdmin()) {
352 if (is_array($stopwords) && !empty($stopwords)) {
353 $this->administrationRepository
->saveStopWords($stopwords);
355 if (is_array($keywords) && !empty($keywords)) {
356 $this->administrationRepository
->saveKeywords($keywords, $pageId);
360 $this->redirect('statisticDetails', NULL
, NULL
, array('pageHash' => $pageHash));
364 * Statistics for a given word id
367 * @param int $pageHash
370 public function wordDetailAction($id = 0, $pageHash = 0) {
371 $rows = $this->getDatabaseConnection()->exec_SELECTgetRows(
372 'index_phash.*, index_section.*, index_rel.*',
373 'index_rel, index_section, index_phash',
374 'index_rel.wid = ' . (int)$id . ' AND index_rel.phash = index_section.phash' . ' AND index_section.phash = index_phash.phash',
376 'index_rel.freq DESC'
379 $this->view
->assignMultiple(array(
389 * @param string $mode
392 public function statisticAction($depth = 1, $mode = 'overview') {
393 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'])) {
394 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'] as $extension => $_objRef) {
395 /** @var \TYPO3\CMS\IndexedSearch\FileContentParser $fileContentParser */
396 $fileContentParser = GeneralUtility
::getUserObj($_objRef);
397 if ($fileContentParser->softInit($extension)) {
398 $this->external_parsers
[$extension] = $fileContentParser;
402 $this->administrationRepository
->external_parsers
= $this->external_parsers
;
404 $allLines = $this->administrationRepository
->getTree($this->pageUid
, $depth, $mode);
406 $this->view
->assignMultiple(array(
407 'levelTranslations' => explode('|', $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.enterSearchLevels')),
409 'pageUid' => $this->pageUid
,
417 * Remove item from index
421 * @param string $mode
424 public function deleteIndexedItemAction($id, $depth = 1, $mode = 'overview') {
425 $this->administrationRepository
->removeIndexedPhashRow($id, $this->pageUid
, $depth);
426 $this->redirect('statistic', NULL
, NULL
, array('depth' => $depth, 'mode' => $mode));
430 * Creates te URI for a backend action
432 * @param string $controller
433 * @param string $action
434 * @param array $parameters
438 protected function getHref($controller, $action, $parameters = []) {
439 $uriBuilder = $this->objectManager
->get(UriBuilder
::class);
440 $uriBuilder->setRequest($this->request
);
441 return $uriBuilder->reset()->uriFor($action, $parameters, $controller);
445 * @return DatabaseConnection
447 protected function getDatabaseConnection() {
448 return $GLOBALS['TYPO3_DB'];
452 * @return BackendUserAuthentication
454 protected function getBackendUserAuthentication() {
455 return $GLOBALS['BE_USER'];
459 * @return LanguageService
461 protected function getLanguageService() {
462 return $GLOBALS['LANG'];