Passed
Pull Request — task/3376-TYPO3_12_compatibili... (#3540)
by Rafael
43:03
created

PageIndexer::authorizeFrontendUser()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 22
rs 9.8333
c 0
b 0
f 0
cc 3
nc 3
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 ApacheSolrForTypo3\Solr\IndexQueue\FrontendHelper;
17
18
use ApacheSolrForTypo3\Solr\Access\Rootline;
19
use ApacheSolrForTypo3\Solr\ConnectionManager;
20
use ApacheSolrForTypo3\Solr\IndexQueue\Item;
21
use ApacheSolrForTypo3\Solr\IndexQueue\Queue;
22
use ApacheSolrForTypo3\Solr\NoSolrConnectionFoundException;
23
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
24
use ApacheSolrForTypo3\Solr\System\Solr\SolrConnection;
25
use ApacheSolrForTypo3\Solr\Typo3PageIndexer;
26
use ApacheSolrForTypo3\Solr\Util;
27
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
28
use Doctrine\DBAL\Exception as DBALException;
29
use Throwable;
30
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
31
use TYPO3\CMS\Core\SingletonInterface;
32
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
33
use TYPO3\CMS\Core\Utility\GeneralUtility;
34
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
35
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
36
use TYPO3\CMS\Frontend\Event\AfterCacheableContentIsGeneratedEvent;
37
use UnexpectedValueException;
38
39
/**
40
 * Index Queue Page Indexer frontend helper to ask the frontend page indexer to
41
 * index the page.
42
 *
43
 * @author Ingo Renner <[email protected]>
44
 */
45
class PageIndexer extends AbstractFrontendHelper
46
{
47
    /**
48
     * This frontend helper's executed action.
49
     *
50
     * @var string
51
     */
52
    protected string $action = 'indexPage';
53
54
    /**
55
     * the page currently being indexed.
56
     *
57
     * @var TypoScriptFrontendController
58
     */
59
    protected TypoScriptFrontendController $page;
60
61
    /**
62
     * Response data
63
     *
64
     * @var array
65
     */
66
    protected array $responseData = [];
67
68
    /**
69
     * Activates a frontend helper by registering for hooks and other
70
     * resources required by the frontend helper to work.
71
     *
72
     * @noinspection PhpUnused
73
     */
74
    public function activate(): void
75
    {
76
        $this->isActivated = true;
77
78
        // indexes fields defined in plugin.tx_solr.index.queue.pages.fields
79
        $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['Indexer']['indexPageSubstitutePageDocument'][PageFieldMappingIndexer::class] = PageFieldMappingIndexer::class;
80
81
        $this->registerAuthorizationService();
82
    }
83
84
    /**
85
     * Returns the status of whether a page was indexed.
86
     *
87
     * @return array Page indexed status.
88
     * @noinspection PhpUnused
89
     */
90
    public function getData(): array
91
    {
92
        return $this->responseData;
93
    }
94
95
    /**
96
     * Gets the access rootline as defined by the request.
97
     *
98
     * @return Rootline The access rootline to use for indexing.
99
     */
100
    protected function getAccessRootline(): Rootline
101
    {
102
        $stringAccessRootline = '';
103
104
        if ($this->request->getParameter('accessRootline')) {
0 ignored issues
show
Bug introduced by
The method getParameter() does not exist on null. ( Ignorable by Annotation )

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

104
        if ($this->request->/** @scrutinizer ignore-call */ getParameter('accessRootline')) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
105
            $stringAccessRootline = $this->request->getParameter('accessRootline');
106
        }
107
108
        return GeneralUtility::makeInstance(Rootline::class, /** @scrutinizer ignore-type */ $stringAccessRootline);
109
    }
110
111
    /**
112
     * Registers an authentication service to authorize / grant the indexer to
113
     * access protected pages.
114
     */
115
    protected function registerAuthorizationService()
116
    {
117
        $overrulingPriority = $this->getHighestAuthenticationServicePriority() + 1;
118
119
        ExtensionManagementUtility::addService(
120
            'solr', // extension key
121
            'auth', // service type
122
            AuthorizationService::class,
123
            // service key
124
            [// service meta data
125
                'title' => 'Solr Indexer Authorization',
126
                'description' => 'Authorizes the Solr Index Queue indexer to access protected pages.',
127
128
                'subtype' => 'getUserFE,authUserFE,getGroupsFE',
129
130
                'available' => true,
131
                'priority' => $overrulingPriority,
132
                'quality' => 100,
133
134
                'os' => '',
135
                'exec' => '',
136
137
                'classFile' => ExtensionManagementUtility::extPath('solr') . 'Classes/IndexQueue/FrontendHelper/AuthorizationService.php',
138
                'className' => AuthorizationService::class,
139
            ]
140
        );
141
    }
142
143
    /**
144
     * Determines the highest priority of all registered authentication
145
     * services.
146
     *
147
     * @return int Highest priority of all registered authentication service
148
     */
149
    protected function getHighestAuthenticationServicePriority(): int
150
    {
151
        $highestPriority = 0;
152
153
        if (is_array($GLOBALS['T3_SERVICES']['auth'] ?? null)) {
154
            foreach ($GLOBALS['T3_SERVICES']['auth'] as $service) {
155
                if ($service['priority'] > $highestPriority) {
156
                    $highestPriority = $service['priority'];
157
                }
158
            }
159
        }
160
161
        return $highestPriority;
162
    }
163
164
    //
165
    // Indexing
166
    //
167
168
    /**
169
     * Generates the current page's URL.
170
     *
171
     * Uses the provided GET parameters, page id and language id.
172
     *
173
     * @return string URL of the current page.
174
     */
175
    protected function generatePageUrl(): string
176
    {
177
        if ($this->request->getParameter('overridePageUrl')) {
178
            return $this->request->getParameter('overridePageUrl');
179
        }
180
181
        /** @var $contentObject ContentObjectRenderer */
182
        $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
183
184
        $typolinkConfiguration = [
185
            'parameter' => $this->page->id,
186
            'linkAccessRestrictedPages' => '1',
187
        ];
188
189
        $language = GeneralUtility::_GET('L');
190
        if (!empty($language)) {
191
            $typolinkConfiguration['additionalParams'] = '&L=' . $language;
192
        }
193
194
        $url = $contentObject->typoLink_URL($typolinkConfiguration);
195
196
        // clean up
197
        if ($url == '') {
198
            $url = '/';
199
        }
200
201
        return $url;
202
    }
203
204
    /**
205
     * Handles the indexing of the page content during AfterCacheableContentIsGeneratedEvent of a generated page.
206
     *
207
     * @param AfterCacheableContentIsGeneratedEvent $event
208
     */
209
    public function __invoke(AfterCacheableContentIsGeneratedEvent $event): void
210
    {
211
        if (!$this->isActivated) {
212
            return;
213
        }
214
215
        $this->logger = GeneralUtility::makeInstance(SolrLogManager::class, self::class);
216
217
        $this->page = $event->getController();
218
        $configuration = Util::getSolrConfiguration();
219
220
        $logPageIndexed = $configuration->getLoggingIndexingPageIndexed();
221
        if (!$this->page->config['config']['index_enable'] ?? false) {
222
            if ($logPageIndexed) {
223
                $this->logger->log(
0 ignored issues
show
Bug introduced by
The method log() does not exist on null. ( Ignorable by Annotation )

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

223
                $this->logger->/** @scrutinizer ignore-call */ 
224
                               log(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
224
                    SolrLogManager::ERROR,
225
                    'Indexing is disabled. Set config.index_enable = 1 .'
226
                );
227
            }
228
            return;
229
        }
230
231
        try {
232
            $indexQueueItem = $this->getIndexQueueItem();
233
            if (is_null($indexQueueItem)) {
234
                throw new UnexpectedValueException('Can not get index queue item', 1482162337);
235
            }
236
237
            $solrConnection = $this->getSolrConnection($indexQueueItem);
238
239
            /** @var $indexer Typo3PageIndexer */
240
            $indexer = GeneralUtility::makeInstance(Typo3PageIndexer::class, /** @scrutinizer ignore-type */ $this->page);
241
            $indexer->setSolrConnection($solrConnection);
242
            $indexer->setPageAccessRootline($this->getAccessRootline());
243
            $indexer->setPageUrl($this->generatePageUrl());
244
            $indexer->setMountPointParameter($GLOBALS['TSFE']->MP);
245
            $indexer->setIndexQueueItem($indexQueueItem);
246
247
            $this->responseData['pageIndexed'] = (int)$indexer->indexPage();
248
            $this->responseData['originalPageDocument'] = (array)$indexer->getPageSolrDocument();
249
            $this->responseData['solrConnection'] = [
250
                'rootPage' => $indexQueueItem->getRootPageUid(),
251
                'sys_language_uid' => Util::getLanguageUid(),
252
                'solr' => (string)$solrConnection->getNode('write'),
253
            ];
254
255
            $documentsSentToSolr = $indexer->getDocumentsSentToSolr();
256
            foreach ($documentsSentToSolr as $document) {
257
                $this->responseData['documentsSentToSolr'][] = (array)$document;
258
            }
259
        } catch (Throwable $e) {
260
            if ($configuration->getLoggingExceptions()) {
261
                $this->logger->log(
262
                    SolrLogManager::ERROR,
263
                    'Exception while trying to index page ' . $this->page->id,
264
                    [
265
                        $e->__toString(),
266
                    ]
267
                );
268
            }
269
        }
270
271
        if ($logPageIndexed) {
272
            $success = $this->responseData['pageIndexed'] ? 'Success' : 'Failed';
273
            $severity = $this->responseData['pageIndexed'] ? SolrLogManager::NOTICE : SolrLogManager::ERROR;
274
275
            $this->logger->log(
276
                $severity,
277
                'Page indexed: ' . $success,
278
                $this->responseData
279
            );
280
        }
281
    }
282
283
    /**
284
     * Gets the solr connection to use for indexing the page based on the
285
     * Index Queue item's properties.
286
     *
287
     * @param Item $indexQueueItem
288
     * @return SolrConnection Solr server connection
289
     * @throws AspectNotFoundException
290
     * @throws NoSolrConnectionFoundException
291
     * @throws DBALDriverException
292
     */
293
    protected function getSolrConnection(Item $indexQueueItem): SolrConnection
294
    {
295
        /** @var $connectionManager ConnectionManager */
296
        $connectionManager = GeneralUtility::makeInstance(ConnectionManager::class);
297
298
        return $connectionManager->getConnectionByRootPageId(
299
            $indexQueueItem->getRootPageUid(),
0 ignored issues
show
Bug introduced by
It seems like $indexQueueItem->getRootPageUid() can also be of type null; however, parameter $pageId of ApacheSolrForTypo3\Solr\...onnectionByRootPageId() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

299
            /** @scrutinizer ignore-type */ $indexQueueItem->getRootPageUid(),
Loading history...
300
            Util::getLanguageUid()
301
        );
302
    }
303
304
    /**
305
     * This method retrieves the item from the index queue, that is indexed in this request.
306
     *
307
     * @return Item|null
308
     * @throws DBALDriverException
309
     * @throws DBALException
310
     */
311
    protected function getIndexQueueItem(): ?Item
312
    {
313
        /** @var $indexQueue Queue */
314
        $indexQueue = GeneralUtility::makeInstance(Queue::class);
315
        return $indexQueue->getItem($this->request->getParameter('item'));
316
    }
317
}
318