Failed Conditions
Pull Request — main (#3637)
by Benni
34:26
created

PageIndexer   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 255
Duplicated Lines 0 %

Test Coverage

Coverage 75.89%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 26
eloc 97
c 2
b 0
f 0
dl 0
loc 255
ccs 85
cts 112
cp 0.7589
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getData() 0 3 1
A activate() 0 8 1
A getHighestAuthenticationServicePriority() 0 13 4
A generatePageUrl() 0 27 4
A getAccessRootline() 0 9 2
A getIndexQueueItem() 0 5 1
A registerAuthorizationService() 0 22 1
A getSolrConnection() 0 8 1
C __invoke() 0 71 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\DebugWriter;
24
use ApacheSolrForTypo3\Solr\System\Logging\SolrLogManager;
25
use ApacheSolrForTypo3\Solr\System\Solr\SolrConnection;
26
use ApacheSolrForTypo3\Solr\Typo3PageIndexer;
27
use ApacheSolrForTypo3\Solr\Util;
28
use Doctrine\DBAL\Exception as DBALException;
29
use Throwable;
30
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
31
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
32
use TYPO3\CMS\Core\Utility\GeneralUtility;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Core\Utility\GeneralUtility was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
33
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Frontend\Conte...t\ContentObjectRenderer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
35
use TYPO3\CMS\Frontend\Event\AfterCacheableContentIsGeneratedEvent;
36
use UnexpectedValueException;
37
38
/**
39
 * Index Queue Page Indexer frontend helper to ask the frontend page indexer to
40
 * index the page.
41
 *
42
 * @author Ingo Renner <[email protected]>
43
 */
44
class PageIndexer extends AbstractFrontendHelper
45
{
46
    /**
47
     * This frontend helper's executed action.
48
     */
49
    protected string $action = 'indexPage';
50
51
    /**
52
     * the page currently being indexed.
53
     */
54
    protected TypoScriptFrontendController $page;
55
56
    /**
57
     * Response data
58
     */
59
    protected array $responseData = [];
60
61
    /**
62
     * Activates a frontend helper by registering for hooks and other
63
     * resources required by the frontend helper to work.
64
     *
65
     * @noinspection PhpUnused
66
     */
67 62
    public function activate(): void
68
    {
69 62
        $this->isActivated = true;
70
71
        // indexes fields defined in plugin.tx_solr.index.queue.pages.fields
72 62
        $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['solr']['Indexer']['indexPageSubstitutePageDocument'][PageFieldMappingIndexer::class] = PageFieldMappingIndexer::class;
73
74 62
        $this->registerAuthorizationService();
75
    }
76
77
    /**
78
     * Returns the status of whether a page was indexed.
79
     *
80
     * @return array Page indexed status.
81
     * @noinspection PhpUnused
82
     */
83 62
    public function getData(): array
84
    {
85 62
        return $this->responseData;
86
    }
87
88
    /**
89
     * Gets the access rootline as defined by the request.
90
     *
91
     * @return Rootline The access rootline to use for indexing.
92
     */
93 62
    protected function getAccessRootline(): Rootline
94
    {
95 62
        $stringAccessRootline = '';
96
97 62
        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

97
        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...
98 2
            $stringAccessRootline = $this->request->getParameter('accessRootline');
99
        }
100
101 62
        return GeneralUtility::makeInstance(Rootline::class, /** @scrutinizer ignore-type */ $stringAccessRootline);
102
    }
103
104
    /**
105
     * Registers an authentication service to authorize / grant the indexer to
106
     * access protected pages.
107
     */
108 62
    protected function registerAuthorizationService(): void
109
    {
110 62
        $overrulingPriority = $this->getHighestAuthenticationServicePriority() + 1;
111
112 62
        ExtensionManagementUtility::addService(
113 62
            'solr', // extension key
114 62
            'auth', // service type
115 62
            AuthorizationService::class,
116
            // service key
117 62
            [// service meta data
118 62
                'title' => 'Solr Indexer Authorization',
119 62
                'description' => 'Authorizes the Solr Index Queue indexer to access protected pages.',
120
121 62
                'subtype' => 'getUserFE,authUserFE,getGroupsFE',
122
123 62
                'available' => true,
124 62
                'priority' => $overrulingPriority,
125 62
                'quality' => 100,
126
127 62
                'os' => '',
128 62
                'exec' => '',
129 62
                'className' => AuthorizationService::class,
130 62
            ]
131 62
        );
132
    }
133
134
    /**
135
     * Determines the highest priority of all registered authentication
136
     * services.
137
     *
138
     * @return int Highest priority of all registered authentication service
139
     */
140 62
    protected function getHighestAuthenticationServicePriority(): int
141
    {
142 62
        $highestPriority = 0;
143
144 62
        if (is_array($GLOBALS['T3_SERVICES']['auth'] ?? null)) {
145 62
            foreach ($GLOBALS['T3_SERVICES']['auth'] as $service) {
146 62
                if ($service['priority'] > $highestPriority) {
147 62
                    $highestPriority = $service['priority'];
148
                }
149
            }
150
        }
151
152 62
        return $highestPriority;
153
    }
154
155
    //
156
    // Indexing
157
    //
158
159
    /**
160
     * Generates the current page's URL as string.
161
     * Uses the provided GET parameters, page id and language id.
162
     */
163 62
    protected function generatePageUrl(): string
164
    {
165 62
        if ($this->request->getParameter('overridePageUrl')) {
166
            return $this->request->getParameter('overridePageUrl');
167
        }
168
169
        /* @var ContentObjectRenderer $contentObject */
170 62
        $contentObject = GeneralUtility::makeInstance(ContentObjectRenderer::class);
171
172 62
        $typolinkConfiguration = [
173 62
            'parameter' => $this->page->id,
174 62
            'linkAccessRestrictedPages' => '1',
175 62
        ];
176
177 62
        $language = GeneralUtility::_GET('L');
178 62
        if (!empty($language)) {
179
            $typolinkConfiguration['additionalParams'] = '&L=' . $language;
180
        }
181
182 62
        $url = $contentObject->typoLink_URL($typolinkConfiguration);
183
184
        // clean up
185 62
        if ($url == '') {
186
            $url = '/';
187
        }
188
189 62
        return $url;
190
    }
191
192
    /**
193
     * Handles the indexing of the page content during AfterCacheableContentIsGeneratedEvent of a generated page.
194
     */
195 69
    public function __invoke(AfterCacheableContentIsGeneratedEvent $event): void
196
    {
197 69
        if (!$this->isActivated) {
198 38
            return;
199
        }
200
201 62
        $this->logger = new SolrLogManager(__CLASS__, GeneralUtility::makeInstance(DebugWriter::class));
202
203 62
        $this->page = $event->getController();
204 62
        $configuration = Util::getSolrConfiguration();
205
206 62
        $logPageIndexed = $configuration->getLoggingIndexingPageIndexed();
207 62
        if (!($this->page->config['config']['index_enable'] ?? false)) {
208
            if ($logPageIndexed) {
209
                $this->logger->log(
210
                    SolrLogManager::ERROR,
211
                    'Indexing is disabled. Set config.index_enable = 1 .'
212
                );
213
            }
214
            return;
215
        }
216
217
        try {
218 62
            $indexQueueItem = $this->getIndexQueueItem();
219 62
            if (is_null($indexQueueItem)) {
220
                throw new UnexpectedValueException('Can not get index queue item', 1482162337);
221
            }
222
223 62
            $solrConnection = $this->getSolrConnection($indexQueueItem);
224
225
            /* @var Typo3PageIndexer $indexer */
226 62
            $indexer = GeneralUtility::makeInstance(Typo3PageIndexer::class, /** @scrutinizer ignore-type */ $this->page);
227 62
            $indexer->setSolrConnection($solrConnection);
228 62
            $indexer->setPageAccessRootline($this->getAccessRootline());
229 62
            $indexer->setPageUrl($this->generatePageUrl());
230 62
            $indexer->setMountPointParameter($GLOBALS['TSFE']->MP);
231 62
            $indexer->setIndexQueueItem($indexQueueItem);
232
233 62
            $this->responseData['pageIndexed'] = (int)$indexer->indexPage();
234 62
            $this->responseData['originalPageDocument'] = (array)$indexer->getPageSolrDocument();
235 62
            $this->responseData['solrConnection'] = [
236 62
                'rootPage' => $indexQueueItem->getRootPageUid(),
237 62
                'sys_language_uid' => Util::getLanguageUid(),
238 62
                'solr' => (string)$solrConnection->getNode('write'),
239 62
            ];
240
241 62
            $documentsSentToSolr = $indexer->getDocumentsSentToSolr();
242 62
            foreach ($documentsSentToSolr as $document) {
243 62
                $this->responseData['documentsSentToSolr'][] = (array)$document;
244
            }
245
        } catch (Throwable $e) {
246
            $this->responseData['pageIndexed'] = false;
247
            if ($configuration->getLoggingExceptions()) {
248
                $this->logger->log(
249
                    SolrLogManager::ERROR,
250
                    'Exception while trying to index page ' . $this->page->id,
251
                    [
252
                        $e->__toString(),
253
                    ]
254
                );
255
            }
256
        }
257
258 62
        if ($logPageIndexed) {
259
            $success = $this->responseData['pageIndexed'] ? 'Success' : 'Failed';
260
            $severity = $this->responseData['pageIndexed'] ? SolrLogManager::NOTICE : SolrLogManager::ERROR;
261
262
            $this->logger->log(
263
                $severity,
264
                'Page indexed: ' . $success,
265
                $this->responseData
266
            );
267
        }
268
    }
269
270
    /**
271
     * Gets the solr connection to use for indexing the page based on the
272
     * Index Queue item's properties.
273
     *
274
     * @throws AspectNotFoundException
275
     * @throws NoSolrConnectionFoundException
276
     * @throws DBALException
277
     */
278 62
    protected function getSolrConnection(Item $indexQueueItem): SolrConnection
279
    {
280
        /* @var ConnectionManager $connectionManager */
281 62
        $connectionManager = GeneralUtility::makeInstance(ConnectionManager::class);
282
283 62
        return $connectionManager->getConnectionByRootPageId(
284 62
            $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

284
            /** @scrutinizer ignore-type */ $indexQueueItem->getRootPageUid(),
Loading history...
285 62
            Util::getLanguageUid()
286 62
        );
287
    }
288
289
    /**
290
     * This method retrieves the item from the index queue, that is indexed in this request.
291
     *
292
     * @throws DBALException
293
     */
294 62
    protected function getIndexQueueItem(): ?Item
295
    {
296
        /* @var Queue $indexQueue */
297 62
        $indexQueue = GeneralUtility::makeInstance(Queue::class);
298 62
        return $indexQueue->getItem($this->request->getParameter('item'));
299
    }
300
}
301