Passed
Push — master ( 0943a9...56c0bf )
by
unknown
13:33
created

AdministrationController::getServerRequest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\IndexedSearch\Controller;
17
18
use Psr\Http\Message\ResponseInterface;
19
use TYPO3\CMS\Backend\Utility\BackendUtility;
20
use TYPO3\CMS\Backend\View\BackendTemplateView;
21
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
22
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
23
use TYPO3\CMS\Core\Database\ConnectionPool;
24
use TYPO3\CMS\Core\Imaging\Icon;
25
use TYPO3\CMS\Core\Localization\LanguageService;
26
use TYPO3\CMS\Core\Type\Bitmask\Permission;
27
use TYPO3\CMS\Core\Utility\GeneralUtility;
28
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
29
use TYPO3\CMS\Extbase\Mvc\Request;
30
use TYPO3\CMS\Extbase\Mvc\RequestInterface;
31
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
32
use TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository;
33
use TYPO3\CMS\IndexedSearch\Indexer;
34
35
/**
36
 * Administration controller
37
 * @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
38
 */
39
class AdministrationController extends ActionController
40
{
41
    /**
42
     * @var AdministrationRepository
43
     */
44
    protected $administrationRepository;
45
46
    /**
47
     * @var int Current page id
48
     */
49
    protected $pageUid = 0;
50
51
    /**
52
     * @var array External parsers
53
     */
54
    protected $external_parsers = [];
55
56
    /**
57
     * @var array Configuration defined in the Extension Manager
58
     */
59
    protected $indexerConfig = [];
60
61
    /**
62
     * @var bool is metaphone enabled
63
     */
64
    protected $enableMetaphoneSearch = false;
65
66
    /**
67
     * Indexer object
68
     *
69
     * @var \TYPO3\CMS\IndexedSearch\Indexer
70
     */
71
    protected $indexer;
72
73
    /**
74
     * Backend Template Container
75
     *
76
     * @var string
77
     */
78
    protected $defaultViewObjectName = BackendTemplateView::class;
79
80
    /**
81
     * BackendTemplateContainer
82
     *
83
     * @var BackendTemplateView
84
     */
85
    protected $view;
86
87
    /**
88
     * Set up the doc header properly here
89
     *
90
     * @param ViewInterface $view
91
     */
92
    protected function initializeView(ViewInterface $view)
93
    {
94
        if ($view instanceof BackendTemplateView) {
95
            /** @var BackendTemplateView $view */
96
            parent::initializeView($view);
97
            $permissionClause = $this->getBackendUserAuthentication()->getPagePermsClause(Permission::PAGE_SHOW);
98
            $pageRecord = BackendUtility::readPageAccess($this->pageUid, $permissionClause);
99
            if ($pageRecord) {
100
                $view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($pageRecord);
101
            }
102
            $this->generateMenu();
103
            $this->view->getModuleTemplate()->setFlashMessageQueue($this->getFlashMessageQueue());
104
            $view->assign('extensionConfiguration', $this->indexerConfig);
105
        }
106
    }
107
108
    /**
109
     * Generates the action menu
110
     */
111
    protected function generateMenu()
112
    {
113
        $menuItems = [
114
            'index' => [
115
                'controller' => 'Administration',
116
                'action' => 'index',
117
                'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xlf:administration.menu.general')
118
            ],
119
            'pages' => [
120
                'controller' => 'Administration',
121
                'action' => 'pages',
122
                'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xlf:administration.menu.pages')
123
            ],
124
            'externalDocuments' => [
125
                'controller' => 'Administration',
126
                'action' => 'externalDocuments',
127
                'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xlf:administration.menu.externalDocuments')
128
            ],
129
            'statistic' => [
130
                'controller' => 'Administration',
131
                'action' => 'statistic',
132
                'label' => $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xlf:administration.menu.statistic')
133
            ]
134
        ];
135
136
        $menu = $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
137
        $menu->setIdentifier('IndexedSearchModuleMenu');
138
139
        $context = '';
140
        foreach ($menuItems as $menuItemConfig) {
141
            $isActive = $this->request->getControllerActionName() === $menuItemConfig['action'];
142
            $menuItem = $menu->makeMenuItem()
143
                ->setTitle($menuItemConfig['label'])
144
                ->setHref($this->uriBuilder->reset()->uriFor($menuItemConfig['action'], [], $menuItemConfig['controller']))
145
                ->setActive($isActive);
146
            $menu->addMenuItem($menuItem);
147
            if ($isActive) {
148
                $context = $menuItemConfig['label'];
149
            }
150
        }
151
152
        $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
153
        $this->view->getModuleTemplate()->setTitle(
154
            $this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang_mod.xlf:mlang_tabs_tab'),
155
            $context
156
        );
157
    }
158
159
    /**
160
     * Function will be called before every other action
161
     */
162
    public function initializeAction()
163
    {
164
        $this->pageUid = (int)($this->request->getQueryParams()['id'] ?? 0);
165
        $this->indexerConfig = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('indexed_search');
166
        $this->enableMetaphoneSearch = (bool)$this->indexerConfig['enableMetaphoneSearch'];
167
        $this->indexer = GeneralUtility::makeInstance(Indexer::class);
168
169
        parent::initializeAction();
170
    }
171
172
    /**
173
     * Override the action name if found in the uc of the user
174
     *
175
     * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request
176
     * @return ResponseInterface
177
     */
178
    public function processRequest(RequestInterface $request): ResponseInterface
179
    {
180
        $arguments = $request->getArguments();
181
        $beUser = $this->getBackendUserAuthentication();
182
183
        if (is_array($arguments) && isset($arguments['action']) && method_exists($this, $arguments['action'] . 'Action')) {
184
            $action = $arguments['action'];
185
186
            switch ($action) {
187
                case 'saveStopwordsKeywords':
188
                    $action = 'statisticDetails';
189
                    break;
190
                case 'deleteIndexedItem':
191
                    $action = 'statistic';
192
                    break;
193
            }
194
195
            $beUser->uc['indexed_search']['action'] = $action;
196
            $beUser->uc['indexed_search']['arguments'] = $arguments;
197
            $beUser->writeUC();
198
        } elseif (isset($beUser->uc['indexed_search']['action'])) {
199
            if ($request instanceof Request) {
200
                $request->setControllerActionName($beUser->uc['indexed_search']['action']);
201
            }
202
            if (isset($beUser->uc['indexed_search']['arguments'])) {
203
                $request->setArguments($beUser->uc['indexed_search']['arguments']);
0 ignored issues
show
Bug introduced by
The method setArguments() does not exist on TYPO3\CMS\Extbase\Mvc\RequestInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to TYPO3\CMS\Extbase\Mvc\RequestInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

203
                $request->/** @scrutinizer ignore-call */ 
204
                          setArguments($beUser->uc['indexed_search']['arguments']);
Loading history...
204
            }
205
        }
206
207
        return parent::processRequest($request);
208
    }
209
210
    /**
211
     * @param \TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository $administrationRepository
212
     */
213
    public function injectAdministrationRepository(AdministrationRepository $administrationRepository)
214
    {
215
        $this->administrationRepository = $administrationRepository;
216
    }
217
218
    /**
219
     * Index action contains the most important statistics
220
     */
221
    public function indexAction(): ResponseInterface
222
    {
223
        $this->view->assignMultiple([
224
            'records' => $this->administrationRepository->getRecordsNumbers(),
225
            'phash' => $this->administrationRepository->getPageHashTypes()
226
        ]);
227
228
        if ($this->pageUid) {
229
            $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
230
                ->getQueryBuilderForTable('index_stat_word')
231
                ->expr();
232
233
            $last24hours = $expressionBuilder->gt('tstamp', $GLOBALS['EXEC_TIME'] - 86400);
234
            $last30days = $expressionBuilder->gt('tstamp', $GLOBALS['EXEC_TIME'] - 30 * 86400);
235
236
            $this->view->assignMultiple([
237
                'pageUid' => $this->pageUid,
238
                'all' => $this->administrationRepository->getGeneralSearchStatistic('', $this->pageUid),
239
                'last24hours' => $this->administrationRepository->getGeneralSearchStatistic($last24hours, $this->pageUid),
240
                'last30days' => $this->administrationRepository->getGeneralSearchStatistic($last30days, $this->pageUid),
241
            ]);
242
        }
243
244
        return $this->htmlResponse();
245
    }
246
247
    /**
248
     * Statistics for pages
249
     */
250
    public function pagesAction(): ResponseInterface
251
    {
252
        $this->view->assign('records', $this->administrationRepository->getPageStatistic());
253
254
        return $this->htmlResponse();
255
    }
256
257
    /**
258
     * Statistics for external documents
259
     */
260
    public function externalDocumentsAction(): ResponseInterface
261
    {
262
        $this->view->assign('records', $this->administrationRepository->getExternalDocumentsStatistic());
263
264
        return $this->htmlResponse();
265
    }
266
267
    /**
268
     * Statistics for a given page hash
269
     *
270
     * @param int $pageHash
271
     */
272
    public function statisticDetailsAction($pageHash = 0): ResponseInterface
273
    {
274
        $pageHash = (int)$pageHash;
275
        // Set back button
276
        $icon = $this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-up', Icon::SIZE_SMALL);
277
        $backButton = $this->view->getModuleTemplate()->getDocHeaderComponent()
278
            ->getButtonBar()->makeLinkButton()
279
            ->setTitle($this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xlf:administration.back'))
280
            ->setIcon($icon)
281
            ->setHref($this->uriBuilder->reset()->uriFor('statistic', [], 'Administration'));
282
        $this->view->getModuleTemplate()->getDocHeaderComponent()
283
            ->getButtonBar()->addButton($backButton);
284
285
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_phash');
286
        $pageHashRow = $queryBuilder
287
            ->select('*')
288
            ->from('index_phash')
289
            ->where(
290
                $queryBuilder->expr()->eq(
291
                    'phash',
292
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
293
                )
294
            )
295
            ->execute()
296
            ->fetch();
297
298
        if (!is_array($pageHashRow)) {
299
            $this->redirect('statistic');
300
        }
301
302
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_debug');
303
        $debugRow = $queryBuilder
304
            ->select('debuginfo')
305
            ->from('index_debug')
306
            ->where(
307
                $queryBuilder->expr()->eq(
308
                    'phash',
309
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
310
                )
311
            )
312
            ->execute()
313
            ->fetch();
314
        $debugInfo = [];
315
        $lexer = '';
316
        if (is_array($debugRow)) {
317
            $debugInfo = json_decode($debugRow['debuginfo'], true);
318
            $lexer = $debugInfo['lexer'];
319
            unset($debugInfo['lexer']);
320
        }
321
        $pageRecord = BackendUtility::getRecord('pages', $pageHashRow['data_page_id']);
322
        $keywords = is_array($pageRecord) ? array_flip(GeneralUtility::trimExplode(',', $pageRecord['keywords'], true)) : [];
323
324
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_words');
325
        $wordRecords = $queryBuilder
326
            ->select('index_words.*', 'index_rel.*')
327
            ->from('index_words')
328
            ->from('index_rel')
329
            ->where(
330
                $queryBuilder->expr()->eq(
331
                    'index_rel.phash',
332
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
333
                ),
334
                $queryBuilder->expr()->eq(
335
                    'index_words.wid',
336
                    $queryBuilder->quoteIdentifier('index_rel.wid')
337
                )
338
            )
339
            ->orderBy('index_words.baseword')
340
            ->execute()
341
            ->fetchAll();
342
        foreach ($wordRecords as $id => $row) {
343
            if (isset($keywords[$row['baseword']])) {
344
                $wordRecords[$id]['is_keyword'] = true;
345
            }
346
        }
347
        $metaphoneRows = $metaphone = [];
348
        if ($this->enableMetaphoneSearch && is_array($wordRecords)) {
349
            // Group metaphone hash
350
            foreach ($wordRecords as $row) {
351
                $metaphoneRows[$row['metaphone']][] = $row['baseword'];
352
            }
353
354
            foreach ($metaphoneRows as $hash => $words) {
355
                if (count($words) > 1) {
356
                    $metaphone[] = [
357
                        'metaphone' => $this->indexer->metaphone($words[0], 1), $hash,
358
                        'words' => $words,
359
                        'hash' => $hash
360
                    ];
361
                }
362
            }
363
        }
364
365
        // sections
366
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_section');
367
        $sections = $queryBuilder
368
            ->select('*')
369
            ->from('index_section')
370
            ->where(
371
                $queryBuilder->expr()->eq(
372
                    'phash',
373
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
374
                )
375
            )
376
            ->execute()
377
            ->fetchAll();
378
379
        // top words
380
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_words');
381
        $topCountWords = $queryBuilder
382
            ->select('index_words.baseword', 'index_words.metaphone', 'index_rel.*')
383
            ->from('index_words')
384
            ->from('index_rel')
385
            ->setMaxResults(20)
386
            ->where(
387
                $queryBuilder->expr()->eq(
388
                    'index_rel.phash',
389
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
390
                ),
391
                $queryBuilder->expr()->eq(
392
                    'index_words.is_stopword',
393
                    $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
394
                ),
395
                $queryBuilder->expr()->eq(
396
                    'index_words.wid',
397
                    $queryBuilder->quoteIdentifier('index_rel.wid')
398
                )
399
            )
400
            ->orderBy('index_rel.count', 'DESC')
401
            ->execute()
402
            ->fetchAll();
403
404
        // top frequency
405
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_words');
406
        $topFrequency = $queryBuilder
407
            ->select('index_words.baseword', 'index_words.metaphone', 'index_rel.*')
408
            ->from('index_words')
409
            ->from('index_rel')
410
            ->setMaxResults(20)
411
            ->where(
412
                $queryBuilder->expr()->eq(
413
                    'index_rel.phash',
414
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
415
                ),
416
                $queryBuilder->expr()->eq(
417
                    'index_words.is_stopword',
418
                    $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
419
                ),
420
                $queryBuilder->expr()->eq(
421
                    'index_words.wid',
422
                    $queryBuilder->quoteIdentifier('index_rel.wid')
423
                )
424
            )
425
            ->orderBy('index_rel.freq', 'DESC')
426
            ->execute()
427
            ->fetchAll();
428
429
        $this->view->assignMultiple([
430
            'phash' => (int)$pageHash,
431
            'phashRow' => $pageHashRow,
432
            'words' => $wordRecords,
433
            'sections' => $sections,
434
            'topCount' => $topCountWords,
435
            'topFrequency' => $topFrequency,
436
            'debug' => $debugInfo,
437
            'lexer' => $lexer,
438
            'metaphone' => $metaphone,
439
            'page' => $pageRecord,
440
            'keywords' => $keywords
441
        ]);
442
443
        return $this->htmlResponse();
444
    }
445
446
    /**
447
     * Save stop words and keywords
448
     *
449
     * @param string $pageHash
450
     * @param int $pageId
451
     * @param array $stopwords
452
     * @param array $keywords
453
     */
454
    public function saveStopwordsKeywordsAction($pageHash, $pageId, $stopwords = [], $keywords = [])
455
    {
456
        if ($this->getBackendUserAuthentication()->isAdmin()) {
457
            if (is_array($stopwords) && !empty($stopwords)) {
458
                $this->administrationRepository->saveStopWords($stopwords);
459
            }
460
            if (is_array($keywords) && !empty($keywords)) {
461
                $this->administrationRepository->saveKeywords($keywords, $pageId);
462
            }
463
        }
464
465
        $this->redirect('statisticDetails', null, null, ['pageHash' => $pageHash]);
466
    }
467
468
    /**
469
     * Statistics for a given word id
470
     *
471
     * @param int $id
472
     * @param int $pageHash
473
     */
474
    public function wordDetailAction($id = 0, $pageHash = 0): ResponseInterface
475
    {
476
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_phash');
477
        $rows = $queryBuilder
478
            ->select('index_phash.*', 'index_section.*', 'index_rel.*')
479
            ->from('index_rel')
480
            ->from('index_section')
481
            ->from('index_phash')
482
            ->where(
483
                $queryBuilder->expr()->eq(
484
                    'index_rel.wid',
485
                    $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
486
                ),
487
                $queryBuilder->expr()->eq(
488
                    'index_rel.phash',
489
                    $queryBuilder->quoteIdentifier('index_section.phash')
490
                ),
491
                $queryBuilder->expr()->eq(
492
                    'index_section.phash',
493
                    $queryBuilder->quoteIdentifier('index_phash.phash')
494
                )
495
            )
496
            ->orderBy('index_rel.freq', 'desc')
497
            ->execute()
498
            ->fetchAll();
499
500
        $this->view->assignMultiple([
501
            'rows' => $rows,
502
            'phash' => $pageHash
503
        ]);
504
505
        return $this->htmlResponse();
506
    }
507
508
    /**
509
     * General statistics
510
     *
511
     * @param int $depth
512
     * @param string $mode
513
     */
514
    public function statisticAction($depth = 1, $mode = 'overview'): ResponseInterface
515
    {
516
        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'] ?? [] as $extension => $className) {
517
            /** @var \TYPO3\CMS\IndexedSearch\FileContentParser $fileContentParser */
518
            $fileContentParser = GeneralUtility::makeInstance($className);
519
            if ($fileContentParser->softInit($extension)) {
520
                $this->external_parsers[$extension] = $fileContentParser;
521
            }
522
        }
523
        $this->administrationRepository->external_parsers = $this->external_parsers;
524
525
        $allLines = $this->administrationRepository->getTree($this->pageUid, $depth, $mode);
526
527
        $this->view->assignMultiple([
528
            'levelTranslations' => explode('|', $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.enterSearchLevels')),
529
            'tree' => $allLines,
530
            'pageUid' => $this->pageUid,
531
            'mode' => $mode,
532
            'depth' => $depth
533
        ]);
534
535
        return $this->htmlResponse();
536
    }
537
538
    /**
539
     * Remove item from index
540
     *
541
     * @param string $id
542
     * @param int $depth
543
     * @param string $mode
544
     */
545
    public function deleteIndexedItemAction($id, $depth = 1, $mode = 'overview')
546
    {
547
        $this->administrationRepository->removeIndexedPhashRow($id, $this->pageUid, $depth);
548
        $this->redirect('statistic', null, null, ['depth' => $depth, 'mode' => $mode]);
549
    }
550
551
    /**
552
     * @return BackendUserAuthentication
553
     */
554
    protected function getBackendUserAuthentication()
555
    {
556
        return $GLOBALS['BE_USER'];
557
    }
558
559
    /**
560
     * @return LanguageService
561
     */
562
    protected function getLanguageService()
563
    {
564
        return $GLOBALS['LANG'];
565
    }
566
}
567