[TASK] Removes extra empty lines
[Packages/TYPO3.CMS.git] / typo3 / sysext / indexed_search / Classes / Controller / AdministrationController.php
1 <?php
2 namespace TYPO3\CMS\IndexedSearch\Controller;
3
4 /**
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Backend\View\BackendTemplateView;
19 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
20 use TYPO3\CMS\Core\Database\DatabaseConnection;
21 use TYPO3\CMS\Core\Imaging\Icon;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
24 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
25 use TYPO3\CMS\Extbase\Mvc\Web\Request as WebRequest;
26 use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
27 use TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository;
28 use TYPO3\CMS\IndexedSearch\Indexer;
29 use TYPO3\CMS\Lang\LanguageService;
30
31 /**
32 * Administration controller
33 */
34 class AdministrationController extends ActionController
35 {
36 /**
37 * @var AdministrationRepository
38 */
39 protected $administrationRepository;
40
41 /**
42 * @var int Current page id
43 */
44 protected $pageUid = 0;
45
46 /**
47 * @var array External parsers
48 */
49 protected $external_parsers = array();
50
51 /**
52 * @var array Configuration defined in the Extension Manager
53 */
54 protected $indexerConfig = array();
55
56 /**
57 * @var bool is metaphone enabled
58 */
59 protected $enableMetaphoneSearch = false;
60
61 /**
62 * Indexer object
63 *
64 * @var \TYPO3\CMS\IndexedSearch\Indexer
65 */
66 protected $indexer;
67
68 /**
69 * Backend Template Container
70 *
71 * @var BackendTemplateView
72 */
73 protected $defaultViewObjectName = BackendTemplateView::class;
74
75 /**
76 * BackendTemplateContainer
77 *
78 * @var BackendTemplateView
79 */
80 protected $view;
81
82 /**
83 * Set up the doc header properly here
84 *
85 * @param ViewInterface $view
86 */
87 protected function initializeView(ViewInterface $view)
88 {
89 /** @var BackendTemplateView $view */
90 parent::initializeView($view);
91 $permissionClause = $this->getBackendUserAuthentication()->getPagePermsClause(1);
92 $pageRecord = BackendUtility::readPageAccess($this->pageUid, $permissionClause);
93 $view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($pageRecord);
94 $this->generateMenu();
95 $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
96 }
97
98 /**
99 * Generates the action menu
100 */
101 protected function generateMenu()
102 {
103 $menuItems = [
104 'index' => [
105 'controller' => 'Administration',
106 'action' => 'index',
107 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.general')
108 ],
109 'pages' => [
110 'controller' => 'Administration',
111 'action' => 'pages',
112 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.pages')
113 ],
114 'externalDocuments' => [
115 'controller' => 'Administration',
116 'action' => 'externalDocuments',
117 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.externalDocuments')
118 ],
119 'statistic' => [
120 'controller' => 'Administration',
121 'action' => 'statistic',
122 'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.menu.statistic')
123 ]
124 ];
125 $uriBuilder = $this->objectManager->get(UriBuilder::class);
126 $uriBuilder->setRequest($this->request);
127
128 $menu = $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
129 $menu->setIdentifier('IndexedSearchModuleMenu');
130
131 foreach ($menuItems as $menuItemConfig) {
132 $isActive = $this->request->getControllerActionName() === $menuItemConfig['action'];
133 $menuItem = $menu->makeMenuItem()
134 ->setTitle($menuItemConfig['label'])
135 ->setHref($this->getHref($menuItemConfig['controller'], $menuItemConfig['action']))
136 ->setActive($isActive);
137 $menu->addMenuItem($menuItem);
138 }
139
140 $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
141 }
142
143 /**
144 * Function will be called before every other action
145 *
146 * @return void
147 */
148 public function initializeAction()
149 {
150 $this->pageUid = (int)GeneralUtility::_GET('id');
151 $this->indexerConfig = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['indexed_search']);
152 $this->enableMetaphoneSearch = (bool)$this->indexerConfig['enableMetaphoneSearch'];
153 $this->indexer = GeneralUtility::makeInstance(Indexer::class);
154
155 parent::initializeAction();
156 }
157
158 /**
159 * Override the action name if found in the uc of the user
160 *
161 * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request
162 * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response
163 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
164 */
165 public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response)
166 {
167 $vars = GeneralUtility::_GET('tx_indexedsearch_web_indexedsearchisearch');
168
169 $beUser = $this->getBackendUserAuthentication();
170 if (is_array($vars) && isset($vars['action']) && method_exists($this, $vars['action'] . 'Action')) {
171 $action = $vars['action'];
172
173 switch ($action) {
174 case 'saveStopwordsKeywords':
175 $action = 'statisticDetails';
176 break;
177 case 'deleteIndexedItem':
178 $action = 'statistic';
179 break;
180 }
181
182 $beUser->uc['indexed_search']['action'] = $action;
183 $beUser->uc['indexed_search']['arguments'] = $request->getArguments();
184 $beUser->writeUC();
185 } elseif (isset($beUser->uc['indexed_search']['action'])) {
186 if ($request instanceof WebRequest) {
187 $request->setControllerActionName($beUser->uc['indexed_search']['action']);
188 }
189 if (isset($beUser->uc['indexed_search']['arguments'])) {
190 $request->setArguments($beUser->uc['indexed_search']['arguments']);
191 }
192 }
193
194 parent::processRequest($request, $response);
195 }
196
197 /**
198 * @param \TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository $administrationRepository
199 * @return void
200 */
201 public function injectAdministrationRepository(AdministrationRepository $administrationRepository)
202 {
203 $this->administrationRepository = $administrationRepository;
204 }
205
206 /**
207 * Index action contains the most important statistics
208 *
209 * @return void
210 */
211 public function indexAction()
212 {
213 $this->view->assignMultiple(array(
214 'records' => $this->administrationRepository->getRecordsNumbers(),
215 'phash' => $this->administrationRepository->getPageHashTypes()
216 ));
217
218 if ($this->pageUid) {
219 $last24hours = ' AND tstamp > ' . ($GLOBALS['EXEC_TIME'] - 24 * 60 * 60);
220 $last30days = ' AND tstamp > ' . ($GLOBALS['EXEC_TIME'] - 30 * 24 * 60 * 60);
221
222 $this->view->assignMultiple(array(
223 'pageUid' => $this->pageUid,
224 'all' => $this->administrationRepository->getGeneralSearchStatistic('', $this->pageUid),
225 'last24hours' => $this->administrationRepository->getGeneralSearchStatistic($last24hours, $this->pageUid),
226 'last30days' => $this->administrationRepository->getGeneralSearchStatistic($last30days, $this->pageUid),
227 ));
228 }
229 }
230
231 /**
232 * Statistics for pages
233 *
234 * @return void
235 */
236 public function pagesAction()
237 {
238 $this->view->assign('records', $this->administrationRepository->getPageStatistic());
239 }
240
241 /**
242 * Statistics for external documents
243 *
244 * @return void
245 */
246 public function externalDocumentsAction()
247 {
248 $this->view->assign('records', $this->administrationRepository->getExternalDocumentsStatistic());
249 }
250
251 /**
252 * Statistics for a given page hash
253 *
254 * @param int $pageHash
255 * @return void
256 */
257 public function statisticDetailsAction($pageHash = 0)
258 {
259 // Set back button
260 $icon = $this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-up', Icon::SIZE_SMALL);
261 $backButton = $this->view->getModuleTemplate()->getDocHeaderComponent()
262 ->getButtonBar()->makeLinkButton()
263 ->setTitle($this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xml:administration.back'))
264 ->setIcon($icon)
265 ->setHref($this->getHref('Administration', 'statistic'));
266 $this->view->getModuleTemplate()->getDocHeaderComponent()
267 ->getButtonBar()->addButton($backButton);
268
269 $pageHash = (int)$pageHash;
270 $db = $this->getDatabaseConnection();
271 $pageHashRow = $db->exec_SELECTgetSingleRow('*', 'index_phash', 'phash = ' . (int)$pageHash);
272
273 if (!is_array($pageHashRow)) {
274 $this->redirect('statistic');
275 }
276
277 $debugRow = $db->exec_SELECTgetRows('*', 'index_debug', 'phash = ' . (int)$pageHash);
278 $debugInfo = array();
279 $lexer = '';
280 if (is_array($debugRow)) {
281 $debugInfo = unserialize($debugRow[0]['debuginfo']);
282 $lexer = $debugInfo['lexer'];
283 unset($debugInfo['lexer']);
284 }
285 $pageRecord = BackendUtility::getRecord('pages', $pageHashRow['data_page_id']);
286 $keywords = is_array($pageRecord) ? array_flip(GeneralUtility::trimExplode(',', $pageRecord['keywords'], true)) : array();
287 $wordRecords = $db->exec_SELECTgetRows(
288 'index_words.*, index_rel.*',
289 'index_rel, index_words',
290 'index_rel.phash = ' . (int)$pageHash . ' AND index_words.wid = index_rel.wid',
291 '',
292 'index_words.baseword'
293 );
294 foreach ($wordRecords as $id => $row) {
295 if (isset($keywords[$row['baseword']])) {
296 $wordRecords[$id]['is_keyword'] = true;
297 }
298 }
299 $metaphoneRows = $metaphone = array();
300 if ($this->enableMetaphoneSearch && is_array($wordRecords)) {
301 // Group metaphone hash
302 foreach ($wordRecords as $row) {
303 $metaphoneRows[$row['metaphone']][] = $row['baseword'];
304 }
305
306 foreach ($metaphoneRows as $hash => $words) {
307 if (count($words) > 1) {
308 $metaphone[] = array(
309 'metaphone' => $this->indexer->metaphone($words[0], 1), $hash,
310 'words' => $words,
311 'hash' => $hash
312 );
313 }
314 }
315 }
316 $this->view->assignMultiple(array(
317 'phash' => $pageHash,
318 'phashRow' => $pageHashRow,
319 'words' => $wordRecords,
320 'sections' => $db->exec_SELECTgetRows(
321 '*',
322 'index_section',
323 'index_section.phash = ' . (int)$pageHash
324 ),
325 'topCount' => $db->exec_SELECTgetRows(
326 'index_words.baseword, index_words.metaphone, index_rel.*',
327 'index_rel, index_words',
328 'index_rel.phash = ' . (int)$pageHash . ' AND index_words.wid = index_rel.wid
329 AND index_words.is_stopword=0',
330 '',
331 'index_rel.count DESC',
332 '20'
333 ),
334 'topFrequency' => $db->exec_SELECTgetRows(
335 'index_words.baseword, index_words.metaphone, index_rel.*',
336 'index_rel, index_words',
337 'index_rel.phash = ' . (int)$pageHash . ' AND index_words.wid = index_rel.wid
338 AND index_words.is_stopword=0',
339 '',
340 'index_rel.freq DESC',
341 '20'
342 ),
343 'debug' => $debugInfo,
344 'lexer' => $lexer,
345 'metaphone' => $metaphone,
346 'page' => $pageRecord,
347 'keywords' => $keywords
348 ));
349 }
350
351 /**
352 * Save stop words and keywords
353 *
354 * @param string $pageHash
355 * @param int $pageId
356 * @param array $stopwords
357 * @param array $keywords
358 * @return void
359 */
360 public function saveStopwordsKeywordsAction($pageHash, $pageId, $stopwords = array(), $keywords = array())
361 {
362 if ($this->getBackendUserAuthentication()->isAdmin()) {
363 if (is_array($stopwords) && !empty($stopwords)) {
364 $this->administrationRepository->saveStopWords($stopwords);
365 }
366 if (is_array($keywords) && !empty($keywords)) {
367 $this->administrationRepository->saveKeywords($keywords, $pageId);
368 }
369 }
370
371 $this->redirect('statisticDetails', null, null, array('pageHash' => $pageHash));
372 }
373
374 /**
375 * Statistics for a given word id
376 *
377 * @param int $id
378 * @param int $pageHash
379 * @return void
380 */
381 public function wordDetailAction($id = 0, $pageHash = 0)
382 {
383 $rows = $this->getDatabaseConnection()->exec_SELECTgetRows(
384 'index_phash.*, index_section.*, index_rel.*',
385 'index_rel, index_section, index_phash',
386 'index_rel.wid = ' . (int)$id . ' AND index_rel.phash = index_section.phash' . ' AND index_section.phash = index_phash.phash',
387 '',
388 'index_rel.freq DESC'
389 );
390
391 $this->view->assignMultiple(array(
392 'rows' => $rows,
393 'phash' => $pageHash
394 ));
395 }
396
397 /**
398 * General statistics
399 *
400 * @param int $depth
401 * @param string $mode
402 * @return void
403 */
404 public function statisticAction($depth = 1, $mode = 'overview')
405 {
406 if (is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'])) {
407 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'] as $extension => $_objRef) {
408 /** @var \TYPO3\CMS\IndexedSearch\FileContentParser $fileContentParser */
409 $fileContentParser = GeneralUtility::getUserObj($_objRef);
410 if ($fileContentParser->softInit($extension)) {
411 $this->external_parsers[$extension] = $fileContentParser;
412 }
413 }
414 }
415 $this->administrationRepository->external_parsers = $this->external_parsers;
416
417 $allLines = $this->administrationRepository->getTree($this->pageUid, $depth, $mode);
418
419 $this->view->assignMultiple(array(
420 'levelTranslations' => explode('|', $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.enterSearchLevels')),
421 'tree' => $allLines,
422 'pageUid' => $this->pageUid,
423 'mode' => $mode,
424 'depth' => $depth
425 ));
426 }
427
428 /**
429 * Remove item from index
430 *
431 * @param string $id
432 * @param int $depth
433 * @param string $mode
434 * @return void
435 */
436 public function deleteIndexedItemAction($id, $depth = 1, $mode = 'overview')
437 {
438 $this->administrationRepository->removeIndexedPhashRow($id, $this->pageUid, $depth);
439 $this->redirect('statistic', null, null, array('depth' => $depth, 'mode' => $mode));
440 }
441
442 /**
443 * Creates te URI for a backend action
444 *
445 * @param string $controller
446 * @param string $action
447 * @param array $parameters
448 *
449 * @return string
450 */
451 protected function getHref($controller, $action, $parameters = [])
452 {
453 $uriBuilder = $this->objectManager->get(UriBuilder::class);
454 $uriBuilder->setRequest($this->request);
455 return $uriBuilder->reset()->uriFor($action, $parameters, $controller);
456 }
457
458 /**
459 * @return DatabaseConnection
460 */
461 protected function getDatabaseConnection()
462 {
463 return $GLOBALS['TYPO3_DB'];
464 }
465
466 /**
467 * @return BackendUserAuthentication
468 */
469 protected function getBackendUserAuthentication()
470 {
471 return $GLOBALS['BE_USER'];
472 }
473
474 /**
475 * @return LanguageService
476 */
477 protected function getLanguageService()
478 {
479 return $GLOBALS['LANG'];
480 }
481 }