Passed
Push — master ( 235898...e5aa6f )
by
unknown
14:50
created

AdministrationController::getHref()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 3
dl 0
loc 5
rs 10
c 0
b 0
f 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
        foreach ($menuItems as $menuItemConfig) {
140
            $isActive = $this->request->getControllerActionName() === $menuItemConfig['action'];
141
            $menuItem = $menu->makeMenuItem()
142
                ->setTitle($menuItemConfig['label'])
143
                ->setHref($this->uriBuilder->reset()->uriFor($menuItemConfig['action'], [], $menuItemConfig['controller']))
144
                ->setActive($isActive);
145
            $menu->addMenuItem($menuItem);
146
        }
147
148
        $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
149
    }
150
151
    /**
152
     * Function will be called before every other action
153
     */
154
    public function initializeAction()
155
    {
156
        $this->pageUid = (int)GeneralUtility::_GET('id');
157
        $this->indexerConfig = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('indexed_search');
158
        $this->enableMetaphoneSearch = (bool)$this->indexerConfig['enableMetaphoneSearch'];
159
        $this->indexer = GeneralUtility::makeInstance(Indexer::class);
160
161
        parent::initializeAction();
162
    }
163
164
    /**
165
     * Override the action name if found in the uc of the user
166
     *
167
     * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request
168
     * @return ResponseInterface
169
     */
170
    public function processRequest(RequestInterface $request): ResponseInterface
171
    {
172
        $vars = GeneralUtility::_GET('tx_indexedsearch_web_indexedsearchisearch');
173
174
        $beUser = $this->getBackendUserAuthentication();
175
        if (is_array($vars) && isset($vars['action']) && method_exists($this, $vars['action'] . 'Action')) {
0 ignored issues
show
introduced by
The condition is_array($vars) is always false.
Loading history...
176
            $action = $vars['action'];
177
178
            switch ($action) {
179
                case 'saveStopwordsKeywords':
180
                    $action = 'statisticDetails';
181
                    break;
182
                case 'deleteIndexedItem':
183
                    $action = 'statistic';
184
                    break;
185
            }
186
187
            $beUser->uc['indexed_search']['action'] = $action;
188
            $beUser->uc['indexed_search']['arguments'] = $request->getArguments();
189
            $beUser->writeUC();
190
        } elseif (isset($beUser->uc['indexed_search']['action'])) {
191
            if ($request instanceof Request) {
192
                $request->setControllerActionName($beUser->uc['indexed_search']['action']);
193
            }
194
            if (isset($beUser->uc['indexed_search']['arguments'])) {
195
                $request->setArguments($beUser->uc['indexed_search']['arguments']);
196
            }
197
        }
198
199
        return parent::processRequest($request);
200
    }
201
202
    /**
203
     * @param \TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository $administrationRepository
204
     */
205
    public function injectAdministrationRepository(AdministrationRepository $administrationRepository)
206
    {
207
        $this->administrationRepository = $administrationRepository;
208
    }
209
210
    /**
211
     * Index action contains the most important statistics
212
     */
213
    public function indexAction(): ResponseInterface
214
    {
215
        $this->view->assignMultiple([
216
            'records' => $this->administrationRepository->getRecordsNumbers(),
217
            'phash' => $this->administrationRepository->getPageHashTypes()
218
        ]);
219
220
        if ($this->pageUid) {
221
            $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
222
                ->getQueryBuilderForTable('index_stat_word')
223
                ->expr();
224
225
            $last24hours = $expressionBuilder->gt('tstamp', $GLOBALS['EXEC_TIME'] - 86400);
226
            $last30days = $expressionBuilder->gt('tstamp', $GLOBALS['EXEC_TIME'] - 30 * 86400);
227
228
            $this->view->assignMultiple([
229
                'pageUid' => $this->pageUid,
230
                'all' => $this->administrationRepository->getGeneralSearchStatistic('', $this->pageUid),
231
                'last24hours' => $this->administrationRepository->getGeneralSearchStatistic($last24hours, $this->pageUid),
232
                'last30days' => $this->administrationRepository->getGeneralSearchStatistic($last30days, $this->pageUid),
233
            ]);
234
        }
235
236
        return $this->htmlResponse($this->view->render());
237
    }
238
239
    /**
240
     * Statistics for pages
241
     */
242
    public function pagesAction(): ResponseInterface
243
    {
244
        $this->view->assign('records', $this->administrationRepository->getPageStatistic());
245
246
        return $this->htmlResponse($this->view->render());
247
    }
248
249
    /**
250
     * Statistics for external documents
251
     */
252
    public function externalDocumentsAction(): ResponseInterface
253
    {
254
        $this->view->assign('records', $this->administrationRepository->getExternalDocumentsStatistic());
255
256
        return $this->htmlResponse($this->view->render());
257
    }
258
259
    /**
260
     * Statistics for a given page hash
261
     *
262
     * @param int $pageHash
263
     */
264
    public function statisticDetailsAction($pageHash = 0): ResponseInterface
265
    {
266
        $pageHash = (int)$pageHash;
267
        // Set back button
268
        $icon = $this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-up', Icon::SIZE_SMALL);
269
        $backButton = $this->view->getModuleTemplate()->getDocHeaderComponent()
270
            ->getButtonBar()->makeLinkButton()
271
            ->setTitle($this->getLanguageService()->sL('LLL:EXT:indexed_search/Resources/Private/Language/locallang.xlf:administration.back'))
272
            ->setIcon($icon)
273
            ->setHref($this->uriBuilder->reset()->uriFor('statistic', [], 'Administration'));
274
        $this->view->getModuleTemplate()->getDocHeaderComponent()
275
            ->getButtonBar()->addButton($backButton);
276
277
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_phash');
278
        $pageHashRow = $queryBuilder
279
            ->select('*')
280
            ->from('index_phash')
281
            ->where(
282
                $queryBuilder->expr()->eq(
283
                    'phash',
284
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
285
                )
286
            )
287
            ->execute()
288
            ->fetch();
289
290
        if (!is_array($pageHashRow)) {
291
            $this->redirect('statistic');
292
        }
293
294
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_debug');
295
        $debugRow = $queryBuilder
296
            ->select('debuginfo')
297
            ->from('index_debug')
298
            ->where(
299
                $queryBuilder->expr()->eq(
300
                    'phash',
301
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
302
                )
303
            )
304
            ->execute()
305
            ->fetch();
306
        $debugInfo = [];
307
        $lexer = '';
308
        if (is_array($debugRow)) {
309
            $debugInfo = json_decode($debugRow['debuginfo'], true);
310
            $lexer = $debugInfo['lexer'];
311
            unset($debugInfo['lexer']);
312
        }
313
        $pageRecord = BackendUtility::getRecord('pages', $pageHashRow['data_page_id']);
314
        $keywords = is_array($pageRecord) ? array_flip(GeneralUtility::trimExplode(',', $pageRecord['keywords'], true)) : [];
315
316
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_words');
317
        $wordRecords = $queryBuilder
318
            ->select('index_words.*', 'index_rel.*')
319
            ->from('index_words')
320
            ->from('index_rel')
321
            ->where(
322
                $queryBuilder->expr()->eq(
323
                    'index_rel.phash',
324
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
325
                ),
326
                $queryBuilder->expr()->eq(
327
                    'index_words.wid',
328
                    $queryBuilder->quoteIdentifier('index_rel.wid')
329
                )
330
            )
331
            ->orderBy('index_words.baseword')
332
            ->execute()
333
            ->fetchAll();
334
        foreach ($wordRecords as $id => $row) {
335
            if (isset($keywords[$row['baseword']])) {
336
                $wordRecords[$id]['is_keyword'] = true;
337
            }
338
        }
339
        $metaphoneRows = $metaphone = [];
340
        if ($this->enableMetaphoneSearch && is_array($wordRecords)) {
341
            // Group metaphone hash
342
            foreach ($wordRecords as $row) {
343
                $metaphoneRows[$row['metaphone']][] = $row['baseword'];
344
            }
345
346
            foreach ($metaphoneRows as $hash => $words) {
347
                if (count($words) > 1) {
348
                    $metaphone[] = [
349
                        'metaphone' => $this->indexer->metaphone($words[0], 1), $hash,
350
                        'words' => $words,
351
                        'hash' => $hash
352
                    ];
353
                }
354
            }
355
        }
356
357
        // sections
358
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_section');
359
        $sections = $queryBuilder
360
            ->select('*')
361
            ->from('index_section')
362
            ->where(
363
                $queryBuilder->expr()->eq(
364
                    'phash',
365
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
366
                )
367
            )
368
            ->execute()
369
            ->fetchAll();
370
371
        // top words
372
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_words');
373
        $topCountWords = $queryBuilder
374
            ->select('index_words.baseword', 'index_words.metaphone', 'index_rel.*')
375
            ->from('index_words')
376
            ->from('index_rel')
377
            ->setMaxResults(20)
378
            ->where(
379
                $queryBuilder->expr()->eq(
380
                    'index_rel.phash',
381
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
382
                ),
383
                $queryBuilder->expr()->eq(
384
                    'index_words.is_stopword',
385
                    $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
386
                ),
387
                $queryBuilder->expr()->eq(
388
                    'index_words.wid',
389
                    $queryBuilder->quoteIdentifier('index_rel.wid')
390
                )
391
            )
392
            ->orderBy('index_rel.count', 'DESC')
393
            ->execute()
394
            ->fetchAll();
395
396
        // top frequency
397
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_words');
398
        $topFrequency = $queryBuilder
399
            ->select('index_words.baseword', 'index_words.metaphone', 'index_rel.*')
400
            ->from('index_words')
401
            ->from('index_rel')
402
            ->setMaxResults(20)
403
            ->where(
404
                $queryBuilder->expr()->eq(
405
                    'index_rel.phash',
406
                    $queryBuilder->createNamedParameter($pageHash, \PDO::PARAM_INT)
407
                ),
408
                $queryBuilder->expr()->eq(
409
                    'index_words.is_stopword',
410
                    $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
411
                ),
412
                $queryBuilder->expr()->eq(
413
                    'index_words.wid',
414
                    $queryBuilder->quoteIdentifier('index_rel.wid')
415
                )
416
            )
417
            ->orderBy('index_rel.freq', 'DESC')
418
            ->execute()
419
            ->fetchAll();
420
421
        $this->view->assignMultiple([
422
            'phash' => (int)$pageHash,
423
            'phashRow' => $pageHashRow,
424
            'words' => $wordRecords,
425
            'sections' => $sections,
426
            'topCount' => $topCountWords,
427
            'topFrequency' => $topFrequency,
428
            'debug' => $debugInfo,
429
            'lexer' => $lexer,
430
            'metaphone' => $metaphone,
431
            'page' => $pageRecord,
432
            'keywords' => $keywords
433
        ]);
434
435
        return $this->htmlResponse($this->view->render());
436
    }
437
438
    /**
439
     * Save stop words and keywords
440
     *
441
     * @param string $pageHash
442
     * @param int $pageId
443
     * @param array $stopwords
444
     * @param array $keywords
445
     */
446
    public function saveStopwordsKeywordsAction($pageHash, $pageId, $stopwords = [], $keywords = [])
447
    {
448
        if ($this->getBackendUserAuthentication()->isAdmin()) {
449
            if (is_array($stopwords) && !empty($stopwords)) {
450
                $this->administrationRepository->saveStopWords($stopwords);
451
            }
452
            if (is_array($keywords) && !empty($keywords)) {
453
                $this->administrationRepository->saveKeywords($keywords, $pageId);
454
            }
455
        }
456
457
        $this->redirect('statisticDetails', null, null, ['pageHash' => $pageHash]);
458
    }
459
460
    /**
461
     * Statistics for a given word id
462
     *
463
     * @param int $id
464
     * @param int $pageHash
465
     */
466
    public function wordDetailAction($id = 0, $pageHash = 0): ResponseInterface
467
    {
468
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('index_phash');
469
        $rows = $queryBuilder
470
            ->select('index_phash.*', 'index_section.*', 'index_rel.*')
471
            ->from('index_rel')
472
            ->from('index_section')
473
            ->from('index_phash')
474
            ->where(
475
                $queryBuilder->expr()->eq(
476
                    'index_rel.wid',
477
                    $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
478
                ),
479
                $queryBuilder->expr()->eq(
480
                    'index_rel.phash',
481
                    $queryBuilder->quoteIdentifier('index_section.phash')
482
                ),
483
                $queryBuilder->expr()->eq(
484
                    'index_section.phash',
485
                    $queryBuilder->quoteIdentifier('index_phash.phash')
486
                )
487
            )
488
            ->orderBy('index_rel.freq', 'desc')
489
            ->execute()
490
            ->fetchAll();
491
492
        $this->view->assignMultiple([
493
            'rows' => $rows,
494
            'phash' => $pageHash
495
        ]);
496
497
        return $this->htmlResponse($this->view->render());
498
    }
499
500
    /**
501
     * General statistics
502
     *
503
     * @param int $depth
504
     * @param string $mode
505
     */
506
    public function statisticAction($depth = 1, $mode = 'overview'): ResponseInterface
507
    {
508
        foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['indexed_search']['external_parsers'] ?? [] as $extension => $className) {
509
            /** @var \TYPO3\CMS\IndexedSearch\FileContentParser $fileContentParser */
510
            $fileContentParser = GeneralUtility::makeInstance($className);
511
            if ($fileContentParser->softInit($extension)) {
512
                $this->external_parsers[$extension] = $fileContentParser;
513
            }
514
        }
515
        $this->administrationRepository->external_parsers = $this->external_parsers;
516
517
        $allLines = $this->administrationRepository->getTree($this->pageUid, $depth, $mode);
518
519
        $this->view->assignMultiple([
520
            'levelTranslations' => explode('|', $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.enterSearchLevels')),
521
            'tree' => $allLines,
522
            'pageUid' => $this->pageUid,
523
            'mode' => $mode,
524
            'depth' => $depth
525
        ]);
526
527
        return $this->htmlResponse($this->view->render());
528
    }
529
530
    /**
531
     * Remove item from index
532
     *
533
     * @param string $id
534
     * @param int $depth
535
     * @param string $mode
536
     */
537
    public function deleteIndexedItemAction($id, $depth = 1, $mode = 'overview')
538
    {
539
        $this->administrationRepository->removeIndexedPhashRow($id, $this->pageUid, $depth);
540
        $this->redirect('statistic', null, null, ['depth' => $depth, 'mode' => $mode]);
541
    }
542
543
    /**
544
     * @return BackendUserAuthentication
545
     */
546
    protected function getBackendUserAuthentication()
547
    {
548
        return $GLOBALS['BE_USER'];
549
    }
550
551
    /**
552
     * @return LanguageService
553
     */
554
    protected function getLanguageService()
555
    {
556
        return $GLOBALS['LANG'];
557
    }
558
}
559