Passed
Pull Request — task/3376-TYPO3_12_compatibili... (#3540)
by Rafael
73:47 queued 28:43
created

PageIndexer   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 275
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 26
eloc 98
c 1
b 0
f 0
dl 0
loc 275
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getHighestAuthenticationServicePriority() 0 13 4
A generatePageUrl() 0 27 4
A getData() 0 3 1
A activate() 0 8 1
A getAccessRootline() 0 9 2
A getIndexQueueItem() 0 5 1
A registerAuthorizationService() 0 24 1
A getSolrConnection() 0 8 1
C __invoke() 0 70 11
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 implements SingletonInterface
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
     * @var true
69
     */
70
    protected bool $isActivated = false;
71
72
    /**
73
     * Activates a frontend helper by registering for hooks and other
74
     * resources required by the frontend helper to work.
75
     *
76
     * @noinspection PhpUnused
77
     */
78
    public function activate(): void
79
    {
80
        $this->isActivated = true;
81
82
        // indexes fields defined in plugin.tx_solr.index.queue.pages.fields
83
        $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['Indexer']['indexPageSubstitutePageDocument'][PageFieldMappingIndexer::class] = PageFieldMappingIndexer::class;
84
85
        $this->registerAuthorizationService();
86
    }
87
88
    /**
89
     * Returns the status of whether a page was indexed.
90
     *
91
     * @return array Page indexed status.
92
     * @noinspection PhpUnused
93
     */
94
    public function getData(): array
95
    {
96
        return $this->responseData;
97
    }
98
99
    /**
100
     * Gets the access rootline as defined by the request.
101
     *
102
     * @return Rootline The access rootline to use for indexing.
103
     */
104
    protected function getAccessRootline(): Rootline
105
    {
106
        $stringAccessRootline = '';
107
108
        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

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

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

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